git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/session/container.go (about) 1 package session 2 3 import ( 4 "crypto/ecdsa" 5 "errors" 6 "fmt" 7 8 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" 9 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" 10 cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" 11 frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" 12 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" 13 ) 14 15 // Container represents token of the FrostFS Container session. A session is opened 16 // between any two sides of the system, and implements a mechanism for transferring 17 // the power of attorney of actions to another network member. The session has a 18 // limited validity period, and applies to a strictly defined set of operations. 19 // See methods for details. 20 // 21 // Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session.Token 22 // message. See ReadFromV2 / WriteToV2 methods. 23 // 24 // Instances can be created using built-in var declaration. 25 type Container struct { 26 commonData 27 28 verb ContainerVerb 29 30 cnrSet bool 31 cnr cid.ID 32 } 33 34 // readContext is a contextReader needed for commonData methods. 35 func (x *Container) readContext(c session.TokenContext, checkFieldPresence bool) error { 36 cCnr, ok := c.(*session.ContainerSessionContext) 37 if !ok || cCnr == nil { 38 return fmt.Errorf("invalid context %T", c) 39 } 40 41 x.cnrSet = !cCnr.Wildcard() 42 cnr := cCnr.ContainerID() 43 44 if x.cnrSet { 45 if cnr != nil { 46 err := x.cnr.ReadFromV2(*cnr) 47 if err != nil { 48 return fmt.Errorf("invalid container ID: %w", err) 49 } 50 } else if checkFieldPresence { 51 return errors.New("missing container or wildcard flag") 52 } 53 } else if cnr != nil { 54 return errors.New("container conflicts with wildcard flag") 55 } 56 57 x.verb = ContainerVerb(cCnr.Verb()) 58 59 return nil 60 } 61 62 func (x *Container) readFromV2(m session.Token, checkFieldPresence bool) error { 63 return x.commonData.readFromV2(m, checkFieldPresence, x.readContext) 64 } 65 66 // ReadFromV2 reads Container from the session.Token message. Checks if the 67 // message conforms to FrostFS API V2 protocol. 68 // 69 // See also WriteToV2. 70 func (x *Container) ReadFromV2(m session.Token) error { 71 return x.readFromV2(m, true) 72 } 73 74 func (x Container) writeContext() session.TokenContext { 75 var c session.ContainerSessionContext 76 c.SetWildcard(!x.cnrSet) 77 c.SetVerb(session.ContainerSessionVerb(x.verb)) 78 79 if x.cnrSet { 80 var cnr refs.ContainerID 81 x.cnr.WriteToV2(&cnr) 82 83 c.SetContainerID(&cnr) 84 } 85 86 return &c 87 } 88 89 // WriteToV2 writes Container to the session.Token message. 90 // The message must not be nil. 91 // 92 // See also ReadFromV2. 93 func (x Container) WriteToV2(m *session.Token) { 94 x.writeToV2(m, x.writeContext) 95 } 96 97 // Marshal encodes Container into a binary format of the FrostFS API protocol 98 // (Protocol Buffers with direct field order). 99 // 100 // See also Unmarshal. 101 func (x Container) Marshal() []byte { 102 return x.marshal(x.writeContext) 103 } 104 105 // Unmarshal decodes FrostFS API protocol binary format into the Container 106 // (Protocol Buffers with direct field order). Returns an error describing 107 // a format violation. 108 // 109 // See also Marshal. 110 func (x *Container) Unmarshal(data []byte) error { 111 return x.unmarshal(data, x.readContext) 112 } 113 114 // MarshalJSON encodes Container into a JSON format of the FrostFS API protocol 115 // (Protocol Buffers JSON). 116 // 117 // See also UnmarshalJSON. 118 func (x Container) MarshalJSON() ([]byte, error) { 119 return x.marshalJSON(x.writeContext) 120 } 121 122 // UnmarshalJSON decodes FrostFS API protocol JSON format into the Container 123 // (Protocol Buffers JSON). Returns an error describing a format violation. 124 // 125 // See also MarshalJSON. 126 func (x *Container) UnmarshalJSON(data []byte) error { 127 return x.unmarshalJSON(data, x.readContext) 128 } 129 130 // Sign calculates and writes signature of the Container data. 131 // Returns signature calculation errors. 132 // 133 // Zero Container is unsigned. 134 // 135 // Note that any Container mutation is likely to break the signature, so it is 136 // expected to be calculated as a final stage of Container formation. 137 // 138 // See also VerifySignature. 139 func (x *Container) Sign(key ecdsa.PrivateKey) error { 140 return x.sign(key, x.writeContext) 141 } 142 143 // VerifySignature checks if Container signature is presented and valid. 144 // 145 // Zero Container fails the check. 146 // 147 // See also Sign. 148 func (x Container) VerifySignature() bool { 149 return x.verifySignature(x.writeContext) 150 } 151 152 // ApplyOnlyTo limits session scope to a given author container. 153 // 154 // See also AppliedTo. 155 func (x *Container) ApplyOnlyTo(cnr cid.ID) { 156 x.cnr = cnr 157 x.cnrSet = true 158 } 159 160 // AppliedTo checks if the session is propagated to the given container. 161 // 162 // Zero Container is applied to all author's containers. 163 // 164 // See also ApplyOnlyTo. 165 func (x Container) AppliedTo(cnr cid.ID) bool { 166 return !x.cnrSet || x.cnr.Equals(cnr) 167 } 168 169 // ContainerVerb enumerates container operations. 170 type ContainerVerb int8 171 172 const ( 173 _ ContainerVerb = iota 174 175 VerbContainerPut // Put rpc 176 VerbContainerDelete // Delete rpc 177 VerbContainerSetEACL // SetExtendedACL rpc 178 ) 179 180 // ForVerb specifies the container operation of the session scope. Each 181 // Container is related to the single operation. 182 // 183 // See also AssertVerb. 184 func (x *Container) ForVerb(verb ContainerVerb) { 185 x.verb = verb 186 } 187 188 // AssertVerb checks if Container relates to the given container operation. 189 // 190 // Zero Container relates to zero (unspecified) verb. 191 // 192 // See also ForVerb. 193 func (x Container) AssertVerb(verb ContainerVerb) bool { 194 return x.verb == verb 195 } 196 197 // IssuedBy checks if Container session is issued by the given user. 198 // 199 // See also Container.Issuer. 200 func IssuedBy(cnr Container, id user.ID) bool { 201 return cnr.Issuer().Equals(id) 202 } 203 204 // VerifySessionDataSignature verifies signature of the session data. In practice, 205 // the method is used to authenticate an operation with session data. 206 func (x Container) VerifySessionDataSignature(data, signature []byte) bool { 207 var sigV2 refs.Signature 208 sigV2.SetKey(x.authKey) 209 sigV2.SetScheme(refs.ECDSA_RFC6979_SHA256) 210 sigV2.SetSign(signature) 211 212 var sig frostfscrypto.Signature 213 214 return sig.ReadFromV2(sigV2) == nil && sig.Verify(data) 215 }