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 }