git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/eacl/table.go (about)

     1  package eacl
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"fmt"
     6  
     7  	v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
     8  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
     9  	cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
    10  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
    11  )
    12  
    13  // Table is a group of ContainerEACL records for single container.
    14  //
    15  // Table is compatible with v2 acl.EACLTable message.
    16  type Table struct {
    17  	version version.Version
    18  	cid     *cid.ID
    19  	records []Record
    20  }
    21  
    22  // CID returns identifier of the container that should use given access control rules.
    23  func (t Table) CID() (cID cid.ID, isSet bool) {
    24  	if t.cid != nil {
    25  		cID = *t.cid
    26  		isSet = true
    27  	}
    28  
    29  	return
    30  }
    31  
    32  // SetCID sets identifier of the container that should use given access control rules.
    33  func (t *Table) SetCID(cid cid.ID) {
    34  	t.cid = &cid
    35  }
    36  
    37  // Version returns version of eACL format.
    38  func (t Table) Version() version.Version {
    39  	return t.version
    40  }
    41  
    42  // SetVersion sets version of eACL format.
    43  func (t *Table) SetVersion(version version.Version) {
    44  	t.version = version
    45  }
    46  
    47  // Records returns list of extended ACL rules.
    48  func (t Table) Records() []Record {
    49  	return t.records
    50  }
    51  
    52  // AddRecord adds single eACL rule.
    53  func (t *Table) AddRecord(r *Record) {
    54  	if r != nil {
    55  		t.records = append(t.records, *r)
    56  	}
    57  }
    58  
    59  // ToV2 converts Table to v2 acl.EACLTable message.
    60  //
    61  // Nil Table converts to nil.
    62  func (t *Table) ToV2() *v2acl.Table {
    63  	if t == nil {
    64  		return nil
    65  	}
    66  
    67  	v2 := new(v2acl.Table)
    68  	var cidV2 refs.ContainerID
    69  
    70  	if t.cid != nil {
    71  		t.cid.WriteToV2(&cidV2)
    72  		v2.SetContainerID(&cidV2)
    73  	}
    74  
    75  	if t.records != nil {
    76  		records := make([]v2acl.Record, len(t.records))
    77  		for i := range t.records {
    78  			records[i] = *t.records[i].ToV2()
    79  		}
    80  
    81  		v2.SetRecords(records)
    82  	}
    83  
    84  	var verV2 refs.Version
    85  	t.version.WriteToV2(&verV2)
    86  	v2.SetVersion(&verV2)
    87  
    88  	return v2
    89  }
    90  
    91  // NewTable creates, initializes and returns blank Table instance.
    92  //
    93  // Defaults:
    94  //   - version: version.Current();
    95  //   - container ID: nil;
    96  //   - records: nil;
    97  //   - session token: nil;
    98  //   - signature: nil.
    99  func NewTable() *Table {
   100  	t := new(Table)
   101  	t.SetVersion(version.Current())
   102  
   103  	return t
   104  }
   105  
   106  // CreateTable creates, initializes with parameters and returns Table instance.
   107  func CreateTable(cid cid.ID) *Table {
   108  	t := NewTable()
   109  	t.SetCID(cid)
   110  
   111  	return t
   112  }
   113  
   114  // NewTableFromV2 converts v2 acl.EACLTable message to Table.
   115  func NewTableFromV2(table *v2acl.Table) *Table {
   116  	t := new(Table)
   117  
   118  	if table == nil {
   119  		return t
   120  	}
   121  
   122  	// set version
   123  	if v := table.GetVersion(); v != nil {
   124  		ver := version.Version{}
   125  		ver.SetMajor(v.GetMajor())
   126  		ver.SetMinor(v.GetMinor())
   127  
   128  		t.SetVersion(ver)
   129  	}
   130  
   131  	// set container id
   132  	if id := table.GetContainerID(); id != nil {
   133  		if t.cid == nil {
   134  			t.cid = new(cid.ID)
   135  		}
   136  
   137  		var h [sha256.Size]byte
   138  
   139  		copy(h[:], id.GetValue())
   140  		t.cid.SetSHA256(h)
   141  	}
   142  
   143  	// set eacl records
   144  	v2records := table.GetRecords()
   145  	t.records = make([]Record, len(v2records))
   146  
   147  	for i := range v2records {
   148  		t.records[i] = *NewRecordFromV2(&v2records[i])
   149  	}
   150  
   151  	return t
   152  }
   153  
   154  // Marshal marshals Table into a protobuf binary form.
   155  func (t *Table) Marshal() ([]byte, error) {
   156  	return t.ToV2().StableMarshal(nil), nil
   157  }
   158  
   159  // Unmarshal unmarshals protobuf binary representation of Table.
   160  func (t *Table) Unmarshal(data []byte) error {
   161  	fV2 := new(v2acl.Table)
   162  	if err := fV2.Unmarshal(data); err != nil {
   163  		return err
   164  	}
   165  
   166  	// format checks
   167  	err := checkFormat(fV2)
   168  	if err != nil {
   169  		return err
   170  	}
   171  
   172  	*t = *NewTableFromV2(fV2)
   173  
   174  	return nil
   175  }
   176  
   177  // MarshalJSON encodes Table to protobuf JSON format.
   178  func (t *Table) MarshalJSON() ([]byte, error) {
   179  	return t.ToV2().MarshalJSON()
   180  }
   181  
   182  // UnmarshalJSON decodes Table from protobuf JSON format.
   183  func (t *Table) UnmarshalJSON(data []byte) error {
   184  	tV2 := new(v2acl.Table)
   185  	if err := tV2.UnmarshalJSON(data); err != nil {
   186  		return err
   187  	}
   188  
   189  	err := checkFormat(tV2)
   190  	if err != nil {
   191  		return err
   192  	}
   193  
   194  	*t = *NewTableFromV2(tV2)
   195  
   196  	return nil
   197  }
   198  
   199  // EqualTables compares Table with each other.
   200  func EqualTables(t1, t2 Table) bool {
   201  	cID1, set1 := t1.CID()
   202  	cID2, set2 := t2.CID()
   203  
   204  	if set1 != set2 || cID1 != cID2 ||
   205  		!t1.Version().Equal(t2.Version()) {
   206  		return false
   207  	}
   208  
   209  	rs1, rs2 := t1.Records(), t2.Records()
   210  
   211  	if len(rs1) != len(rs2) {
   212  		return false
   213  	}
   214  
   215  	for i := range len(rs1) {
   216  		if !equalRecords(rs1[i], rs2[i]) {
   217  			return false
   218  		}
   219  	}
   220  
   221  	return true
   222  }
   223  
   224  func checkFormat(v2 *v2acl.Table) error {
   225  	var cID cid.ID
   226  
   227  	cidV2 := v2.GetContainerID()
   228  	if cidV2 == nil {
   229  		return nil
   230  	}
   231  
   232  	err := cID.ReadFromV2(*cidV2)
   233  	if err != nil {
   234  		return fmt.Errorf("could not convert V2 container ID: %w", err)
   235  	}
   236  
   237  	return nil
   238  }