From d8cc00b54cc6a148021e051362b212b7750d846c Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 8 May 2020 10:49:23 +0300 Subject: [PATCH 1/6] Update to neofs-api v0.7.4 --- Makefile | 2 +- docs/service.md | 16 ++++++++++++++-- docs/session.md | 25 ++++++++---------------- service/verify.pb.go | Bin 35203 -> 39615 bytes service/verify.proto | 18 ++++++++++++------ session/service.go | 10 ---------- session/service.pb.go | Bin 27455 -> 21636 bytes session/service.proto | 43 +++++++++++++++--------------------------- 8 files changed, 50 insertions(+), 64 deletions(-) diff --git a/Makefile b/Makefile index 62a92ec..b99682b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PROTO_VERSION=v0.7.3 +PROTO_VERSION=v0.7.4 PROTO_URL=https://github.com/nspcc-dev/neofs-api/archive/$(PROTO_VERSION).tar.gz B=\033[0;1m diff --git a/docs/service.md b/docs/service.md index eef1e49..9ed548e 100644 --- a/docs/service.md +++ b/docs/service.md @@ -17,6 +17,7 @@ - [RequestVerificationHeader.Signature](#service.RequestVerificationHeader.Signature) - [Token](#service.Token) - [Token.Info](#service.Token.Info) + - [TokenLifetime](#service.TokenLifetime) - [service/verify_test.proto](#service/verify_test.proto) @@ -129,10 +130,21 @@ User token granting rights for object manipulation | OwnerID | [bytes](#bytes) | | OwnerID is an owner of manipulation object | | verb | [Token.Info.Verb](#service.Token.Info.Verb) | | Verb is a type of request for which the token is issued | | Address | [refs.Address](#refs.Address) | | Address is an object address for which token is issued | -| Created | [uint64](#uint64) | | Created is an initial epoch of token lifetime | -| ValidUntil | [uint64](#uint64) | | ValidUntil is a last epoch of token lifetime | +| Lifetime | [TokenLifetime](#service.TokenLifetime) | | Lifetime is a lifetime of the session | | SessionKey | [bytes](#bytes) | | SessionKey is a public key of session key | + + + +### Message TokenLifetime +TokenLifetime carries a group of lifetime parameters of the token + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| Created | [uint64](#uint64) | | Created carries an initial epoch of token lifetime | +| ValidUntil | [uint64](#uint64) | | ValidUntil carries a last epoch of token lifetime | + diff --git a/docs/session.md b/docs/session.md index 4a537e6..5ec7402 100644 --- a/docs/session.md +++ b/docs/session.md @@ -30,22 +30,13 @@ ``` -rpc Create(stream CreateRequest) returns (stream CreateResponse); +rpc Create(CreateRequest) returns (CreateResponse); ``` #### Method Create -Create is a method that used to open a trusted session to manipulate -an object. In order to put or delete object client have to obtain session -token with trusted node. Trusted node will modify client's object -(add missing headers, checksums, homomorphic hash) and sign id with -session key. Session is established during 4-step handshake in one gRPC stream - -- First client stream message SHOULD BE type of `CreateRequest_Init`. -- First server stream message SHOULD BE type of `CreateResponse_Unsigned`. -- Second client stream message SHOULD BE type of `CreateRequest_Signed`. -- Second server stream message SHOULD BE type of `CreateResponse_Result`. +Create opens new session between the client and the server | Name | Input | Output | | ---- | ----- | ------ | @@ -56,13 +47,13 @@ session key. Session is established during 4-step handshake in one gRPC stream ### Message CreateRequest - +CreateRequest carries an information necessary for opening a session | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| Init | [service.Token](#service.Token) | | Init is a message to initialize session opening. Carry: owner of manipulation object; ID of manipulation object; token lifetime bounds. | -| Signed | [service.Token](#service.Token) | | Signed Init message response (Unsigned) from server with user private key | +| OwnerID | [bytes](#bytes) | | OwnerID carries an identifier of a session initiator | +| Lifetime | [service.TokenLifetime](#service.TokenLifetime) | | Lifetime carries a lifetime of the session | | Meta | [service.RequestMetaHeader](#service.RequestMetaHeader) | | RequestMetaHeader contains information about request meta headers (should be embedded into message) | | Verify | [service.RequestVerificationHeader](#service.RequestVerificationHeader) | | RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message) | @@ -70,13 +61,13 @@ session key. Session is established during 4-step handshake in one gRPC stream ### Message CreateResponse - +CreateResponse carries an information about the opened session | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| Unsigned | [service.Token](#service.Token) | | Unsigned token with token ID and session public key generated on server side | -| Result | [service.Token](#service.Token) | | Result is a resulting token which can be used for object placing through an trusted intermediary | +| ID | [bytes](#bytes) | | ID carries an identifier of session token | +| SessionKey | [bytes](#bytes) | | SessionKey carries a session public key | diff --git a/service/verify.pb.go b/service/verify.pb.go index 023e6392bb2ee316a7b3ddcc8c6726604981a694..3dadf0b559b9930f8b0dccd14d645b45c1b8f4d7 100644 GIT binary patch delta 4300 zcmZ{nO^6(28pr7|#+_D|fJThLnc9p-jjidfs;;gwNXAW8P!n-kML`d#Pi>v)8GCwS zYc{FX1yL6kHZRB?_99*cKM)#kipqkAJ*?*DLEQD~&8vd=zW-m(^o(L3UaH=DKL5}E zdEU4GYUV!vVDA0Rh5A&#Do6d*((7+{skgHAwpMwgr%G?5+}P-^4Vv>0uRT)^wq?(( z57$O(*=BXuq3rolxzXyj*49U@LAqMry(QF=OwcM_$PFI{|34%ar8LEcZQBE{Kj@G8>56%6;aH<%K3h1kmyf2oc*kLH z`?uL2jH1xK?m*#eI<&hj-~4g$n7Od;)vI?UVE%Uf!qOHl=gxcQo7LtZ_ikPFj_j8E z@cNU#*^;|>U}^i=9J%tLgZ}yEuPVNA<;kD9{QSU&S4>TrAFm0_zNO1&=5AP8oV|Q= zLpXbRZt3W@+R^>D?^gTY(vg|uxtkuFy?lAoBa@3azu7SVK74St`}N`LW-tCNug^t2 z^PgK*>u%8U+T*ZrYgD{`?HxXk27wlh5^T2p0G$#Vxaq99vA6$b(-)K;vm0H_p_zXOJjo-x3K&id-HFxz2J436elLl=2x#xdaS7S0n`tn3gX4V4*bYaY_z^QK~?R zGy=fTb12(w?Q~@|R}@&vwBsxDKo)FqZ8~7lE0jWjA%fAG*}~M8T+%M29V>N8QVEPg zesa*0TCSCxedTYVa$HU1x&%F`!GmB&@Kd78MB6&H{%sL$tc8RsnW)4V5N@Mf$wLRL zDn_EPQz@VvsU)#v=!r@@z>q6Jk#5{mF=CsP_1~4b7_ugE*V)0eSh77?g+x7-f!yfH zuA&GelM1S?GAyMVQTiSr39(EdB}uEcsb|uI8eM%(6f51(5g3^~B(jt!x`420E=8Rt z@=(b(l|+rEjPNN#43Sc`l83fLX;4QZTRp8^DY&v)RM}Br zfy@C61qdW#8Se7W<-tx1`)q6Cs08;zk`|zm?B(Z4&DwDe za&n7n=d=x!Dj6h>WDok#Bg`WNVH6()MFY~fiYvMTDED20GddYk;+8z6{F8|Q51|!O9NMiLI7l> zD`lo7v&R`BoJ0P3~h5}=P+057}6fnmxhbHXpC{GKq z^+`#9hvJ2DhRx9WcOELZuK>6nqPXG zEZin)J9llAoLbO?^MyG90l_U*w$wADNQ%yu+j-yy6KN~i0Sts@1pvkrg{dvX)<0?t zc7$jpd`>-(BE7_T%T@YN9D>)3MkY5vV2bDPZ3ucB2 z(-qv14tOXGqXY=KsTJ~UzdDehHRd!?>gnxqdU=AZDj$<8QAA`;(Wh4qRk9<=SkIOo z&I90bT>8S6{@_;If#Pt>6{#MBAq|=;tLc3~$~}paRTnB%VhqOx3``X^T#XeHM{y<^ z00uLgo}?Re38=?*Tss2DgzZC@1HHrzhuaAk26~1wfFlxq{8Exw82bQLsSNf=l>-Il z=w|O9*qa{kl0vq}DW?K(Tuo7xa;RBCiBoB%Tk_5W^OFEV;1+vm90r5~&-&-y$n*zK z<|Ox7dYK%!NLgY!58TD3LrLR+$u%8B^2P{=s4A%`7W}tuAiN`Z}|D;(q&|_LCF&p13)Ge)8$PH}1V=#k<>Ey>s_J(Br3Cb1R;?^!xqh-07Fi zyARB7{~dh#zLVzbQ!kt7{y$9`4}RY=?F-Ah|8!2gNA}E_eP`#*nMZg0+w{(!X+-A5 zv)4}A7e2Lr@dvZ`C;xr$|Bb75hG5=){E6LG%|F(w$qz5Q*f5_xyx;ur!t&(Opa0O9 O6f0jfCf~huaqmwCMVc=F delta 3378 zcmYk8y~`a%6vnwPN#sqTm53to1(U+?zOcJ@KkmjR5-tk1eEGu3{P6tKt8$(%yg2`N?%h?jyZPMrr{+IixISOI`q+H= z;`RCD;vw_DpMQP#^~L+E`P1Y1AW!EfPTrsD?D#0z=6xJDLmc}xE8X$g!(^K#Y?N_q zsyL<`&6wvHlucZ(n6DYDF|H(>Oj@jPnx%2B?WTzU)3(^ewK8Xiu{0#@>bRaTYTe?a z2Gi&|R&qTUFFtz^wmHx#DGXh7mol~yVA>9#8AXDRirfZ#RG4izQ!%Ev>&UZ9AZbl_ zy6Euj(Hi4$C?;)Ei~|8DF@v6I4Ooq|PWd_-((+TClAM=Dm^5>Rhh*Q|R>Y{q1? z&;(Fn&|%QysN5?+X}~@BJ#niX238y7UeQxx3=GFYS6H{0DLV}#mZ4@z8hS`nY6@_cUcsMa*xV91Kup2d5UH)=nS7t5rkrAw9cbaI zhk1=f#k?mq$Y4X&dluH1lks-U6sAwm}UG zCHRF13d;!5DQ2O^Vn11K5|Mguy#-6?{StSZHTc$0WYs0;KrD2NCneQ%?Z%c~wV?*d z1K%1-w6D*|$&oY4{)Wcvm5g*UdXP52*!-UzItCWyW zg1g+fly2o^&$~)N$XX8S7aM7a}Xrbcgj1N5q8VS z$75ST=VbL#5f+J}Ko&9Ml(*Zv)bZd%lpN^&)~~*uIvVf8MtDzR^iG1DQ|T65gy>qZ&}wn$cgF z(ip~wp!M=g#z0ZBW0%hxX#U!2G*g9MzL1C&pUsdz+dePh;}H?O#mlEtk@1N%B&;p5 z&!zt*Ux*BMiq(jf&;JOWL98RdqFI6Gn}IQMSp3nlM!AM7U!s;M`~>*tTU^i{%U2aY zK{z8qQq6B)diEJLLj>ETC%!V-eS7KtC?%x}E< z)b7t~zn`8T-S}!gyz#^Cx3?Z0&kyci-hJ}TORM?bohNq>?tZyC(={IsN7ek^J8$m( Oy7T#|-O0W0&ioJOLuSVS diff --git a/service/verify.proto b/service/verify.proto index b25cd47..ed360be 100644 --- a/service/verify.proto +++ b/service/verify.proto @@ -58,14 +58,11 @@ message Token { // Address is an object address for which token is issued refs.Address Address = 4 [(gogoproto.nullable) = false, (gogoproto.customtype) = "Address"]; - // Created is an initial epoch of token lifetime - uint64 Created = 5; - - // ValidUntil is a last epoch of token lifetime - uint64 ValidUntil = 6; + // Lifetime is a lifetime of the session + TokenLifetime Lifetime = 5 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; // SessionKey is a public key of session key - bytes SessionKey = 7; + bytes SessionKey = 6; } // TokenInfo is a grouped information about token @@ -75,6 +72,15 @@ message Token { bytes Signature = 8; } +// TokenLifetime carries a group of lifetime parameters of the token +message TokenLifetime { + // Created carries an initial epoch of token lifetime + uint64 Created = 1; + + // ValidUntil carries a last epoch of token lifetime + uint64 ValidUntil = 2; +} + // TODO: for variable token types and version redefine message // Example: // message Token { diff --git a/session/service.go b/session/service.go index 6e293d3..ab87616 100644 --- a/session/service.go +++ b/session/service.go @@ -1,11 +1 @@ package session - -// NewInitRequest returns new initialization CreateRequest from passed Token. -func NewInitRequest(t *Token) *CreateRequest { - return &CreateRequest{Message: &CreateRequest_Init{Init: t}} -} - -// NewSignedRequest returns new signed CreateRequest from passed Token. -func NewSignedRequest(t *Token) *CreateRequest { - return &CreateRequest{Message: &CreateRequest_Signed{Signed: t}} -} diff --git a/session/service.pb.go b/session/service.pb.go index 1088308c46f56a8bbc670655cdb94f03a1fae586..e68c0fdd58e180f56fc7c5b5de292b9c1da029a1 100644 GIT binary patch delta 4753 zcmbVPO^jPt71ktahz)J?+ey+kdT~l)CyvLz&-Rdsm}Vw0Fm0nuQ>2apc|Z3hkJ!)7 z^P9v&6s$_H2i*liP!LOY6<)HSNZBA3u<8mSSiuIdM<6)&`<`Q)X)8*k+_}E@ob!F> z=bm@(uRdJ(&d(R#-`W4Ar6ucXteiyMQ1^G#AhA3rjzcxDoX85Jpci+YB@KvfIbbwgJys-yHO!j(b$%<4>p2mM|&m?1GAV#n?6B;aDgtNaNi{oUtsjZX?|ngc5_jI$XL z1^10L{bBaZXl+7wCR*wKgs+5+aoS=wzp8d;A~iAJ-*G#kXWdh~+02Zf_4MENEt4?$ zIh#WLhvSDYO~q3(6XcnVUN=lsx1a3lx1Z1H*1@wnICw$7cQCK57Y>cj9gg;ET{|K_ zKKtTSD_^iu)JNG&7+78X?&V{j>z1Yx`kyCGj?bOUFD%%4^VFS@T`yYYVY^~RFEFF6 z%;-C2te1<~OnF!-W7{@kqisgVHDkGIMi(ZW2G)J7Kv`j|z^F(0rrE7v-UQ^RRRuz; zW_E07w}8+9jRtHuSZPDM0ZigM*!6*|z^)B6T4+MjYXQK6=^BJ=f*Et8VTIaY)5P5M z43{!kRd>ctAA;b<#jA%e^V7&$$7MH@h zjj;koHOSW>*>-{8!giI0pv;g|F(=g;XxC*$@Oc85874h|GKD%b7sSZ zZKk^cN95p`;9+dQ=NeOjl{B;x9>HhK6-+1=YYjf|On7jY1e)OOlRXj|pgufs5oN*j zSd$DDiyo2+GJX>-G!VU(UmS@BaROl05lZ^Ta0d`=@&u3;W7BE2^Mz+yj_k!V*%Kh^BmT^86RxKjd?4BK!Ym`4>H-J>*Ru(WU9(7 z;0F+`BYIVO=mWt4Z#JAV<|L+Im7#AznK@)T^squqwy)GE0C@J&TD6-ald>A!MJOxa zYD#m`4i$JaxXfD0%j60fm6W6A-|VkTLGCCNWA5WyMkOpIwPvhlJD9&2IyVRdI@Z zW(hcT*ro!zWn<=Kq%{n}HrTN#v)}PUP;*D{A^rS;QxnOhyEf1iaCktO9(HSKY2pJL zz8oc)^9#jjr(dzO?Xf0cng_9tTvbLh@nNH`!YaEMxv*RDtI3wm6U$7>c{gdGiwtWE zN#|Ft$K*jp<`7?*Z$ht853eaCW|FZr`;iUfl`6nN@ zx%iGHS1xm7U0yMe`H2Buatqmviet0ql{~Ms5j~L0Y2HhQMJu;7;5Bn{OIxC9t|-rf zq9rEv-}2RLtdgBL!p|cY?`{7dzGX8socDTBqJ~N7D*qPey-oCw3NPyQ(paybKXEix z_xEm}e%?5nGK#`ZQJ-De*cQCe}6gii_44qu6I+k0M z)ns)$T)tHlR?}xuA*+AbzHn@hR-vHZdF`d9F*|i;W9@(PLmr$T<-#lDAG~HSywtHi zDlUlgH& zuWgNg`Q;Dxe$=KeI=Ge*gdg literal 27455 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 Date: Fri, 8 May 2020 11:08:09 +0300 Subject: [PATCH 2/6] session: implement getters and setters on messages --- service/token.go | 8 ++++---- session/request.go | 11 +++++++++++ session/request_test.go | 29 +++++++++++++++++++++++++++++ session/response.go | 16 ++++++++++++++++ session/response_test.go | 27 +++++++++++++++++++++++++++ session/service.go | 1 - 6 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 session/request.go create mode 100644 session/request_test.go create mode 100644 session/response.go create mode 100644 session/response_test.go delete mode 100644 session/service.go diff --git a/service/token.go b/service/token.go index f431427..78fccfa 100644 --- a/service/token.go +++ b/service/token.go @@ -75,22 +75,22 @@ func (m *Token_Info) SetAddress(addr Address) { } // CreationEpoch is a Created field getter. -func (m Token_Info) CreationEpoch() uint64 { +func (m TokenLifetime) CreationEpoch() uint64 { return m.Created } // SetCreationEpoch is a Created field setter. -func (m *Token_Info) SetCreationEpoch(e uint64) { +func (m *TokenLifetime) SetCreationEpoch(e uint64) { m.Created = e } // ExpirationEpoch is a ValidUntil field getter. -func (m Token_Info) ExpirationEpoch() uint64 { +func (m TokenLifetime) ExpirationEpoch() uint64 { return m.ValidUntil } // SetExpirationEpoch is a ValidUntil field setter. -func (m *Token_Info) SetExpirationEpoch(e uint64) { +func (m *TokenLifetime) SetExpirationEpoch(e uint64) { m.ValidUntil = e } diff --git a/session/request.go b/session/request.go new file mode 100644 index 0000000..4a92c42 --- /dev/null +++ b/session/request.go @@ -0,0 +1,11 @@ +package session + +// GetOwnerID is an OwnerID field getter. +func (m CreateRequest) GetOwnerID() OwnerID { + return m.OwnerID +} + +// SetOwnerID is an OwnerID field setter. +func (m *CreateRequest) SetOwnerID(id OwnerID) { + m.OwnerID = id +} diff --git a/session/request_test.go b/session/request_test.go new file mode 100644 index 0000000..06c62fd --- /dev/null +++ b/session/request_test.go @@ -0,0 +1,29 @@ +package session + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCreateRequestGettersSetters(t *testing.T) { + t.Run("owner ID", func(t *testing.T) { + id := OwnerID{1, 2, 3} + m := new(CreateRequest) + + m.SetOwnerID(id) + + require.Equal(t, id, m.GetOwnerID()) + }) + + t.Run("lifetime", func(t *testing.T) { + e1, e2 := uint64(3), uint64(4) + m := new(CreateRequest) + + m.SetCreationEpoch(e1) + m.SetExpirationEpoch(e2) + + require.Equal(t, e1, m.CreationEpoch()) + require.Equal(t, e2, m.ExpirationEpoch()) + }) +} diff --git a/session/response.go b/session/response.go new file mode 100644 index 0000000..3426d7c --- /dev/null +++ b/session/response.go @@ -0,0 +1,16 @@ +package session + +// GetID is an ID field getter. +func (m CreateResponse) GetID() TokenID { + return m.ID +} + +// SetID is an ID field setter. +func (m *CreateResponse) SetID(id TokenID) { + m.ID = id +} + +// SetSessionKey is a SessionKey field setter. +func (m *CreateResponse) SetSessionKey(key []byte) { + m.SessionKey = key +} diff --git a/session/response_test.go b/session/response_test.go new file mode 100644 index 0000000..0e1de0b --- /dev/null +++ b/session/response_test.go @@ -0,0 +1,27 @@ +package session + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCreateResponseGettersSetters(t *testing.T) { + t.Run("id", func(t *testing.T) { + id := TokenID{1, 2, 3} + m := new(CreateResponse) + + m.SetID(id) + + require.Equal(t, id, m.GetID()) + }) + + t.Run("session key", func(t *testing.T) { + key := []byte{1, 2, 3} + m := new(CreateResponse) + + m.SetSessionKey(key) + + require.Equal(t, key, m.GetSessionKey()) + }) +} diff --git a/session/service.go b/session/service.go deleted file mode 100644 index ab87616..0000000 --- a/session/service.go +++ /dev/null @@ -1 +0,0 @@ -package session From 6d71ea239bb729a8021a39311b1bd790b0331534 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 8 May 2020 11:55:19 +0300 Subject: [PATCH 3/6] session: implement SignedDataSource on CreateRequest --- session/request.go | 47 ++++++++++++++++++++++++++++++ session/request_test.go | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/session/request.go b/session/request.go index 4a92c42..85f563f 100644 --- a/session/request.go +++ b/session/request.go @@ -1,5 +1,19 @@ package session +import ( + "encoding/binary" + "io" + + "github.com/nspcc-dev/neofs-api-go/refs" +) + +const signedRequestDataSize = 0 + + refs.OwnerIDSize + + 8 + + 8 + +var requestEndianness = binary.BigEndian + // GetOwnerID is an OwnerID field getter. func (m CreateRequest) GetOwnerID() OwnerID { return m.OwnerID @@ -9,3 +23,36 @@ func (m CreateRequest) GetOwnerID() OwnerID { func (m *CreateRequest) SetOwnerID(id OwnerID) { m.OwnerID = id } + +func (m CreateRequest) SignedData() ([]byte, error) { + data := make([]byte, m.SignedDataSize()) + + _, err := m.ReadSignedData(data) + if err != nil { + return nil, err + } + + return data, nil +} + +func (m CreateRequest) SignedDataSize() int { + return signedRequestDataSize +} + +func (m CreateRequest) ReadSignedData(p []byte) (int, error) { + sz := m.SignedDataSize() + if len(p) < sz { + return 0, io.ErrUnexpectedEOF + } + + var off int + + off += copy(p[off:], m.GetOwnerID().Bytes()) + + requestEndianness.PutUint64(p[off:], m.CreationEpoch()) + off += 8 + + requestEndianness.PutUint64(p[off:], m.ExpirationEpoch()) + + return sz, nil +} diff --git a/session/request_test.go b/session/request_test.go index 06c62fd..094ca66 100644 --- a/session/request_test.go +++ b/session/request_test.go @@ -27,3 +27,66 @@ func TestCreateRequestGettersSetters(t *testing.T) { require.Equal(t, e2, m.ExpirationEpoch()) }) } + +func TestCreateRequest_SignedData(t *testing.T) { + var ( + id = OwnerID{1, 2, 3} + e1 = uint64(1) + e2 = uint64(2) + ) + + // create new message + m := new(CreateRequest) + + // fill the fields + m.SetOwnerID(id) + m.SetCreationEpoch(e1) + m.SetExpirationEpoch(e2) + + // calculate initial signed data + d, err := m.SignedData() + require.NoError(t, err) + + items := []struct { + change func() + reset func() + }{ + { // OwnerID + change: func() { + id2 := id + id2[0]++ + m.SetOwnerID(id2) + }, + reset: func() { + m.SetOwnerID(id) + }, + }, + { // CreationEpoch + change: func() { + m.SetCreationEpoch(e1 + 1) + }, + reset: func() { + m.SetCreationEpoch(e1) + }, + }, + { // ExpirationEpoch + change: func() { + m.SetExpirationEpoch(e2 + 1) + }, + reset: func() { + m.SetExpirationEpoch(e2) + }, + }, + } + + for _, item := range items { + item.change() + + d2, err := m.SignedData() + require.NoError(t, err) + + require.NotEqual(t, d, d2) + + item.reset() + } +} From b079a7604f19ef5aa5fa4abed0cb7a394fb14d34 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 8 May 2020 12:34:16 +0300 Subject: [PATCH 4/6] session: implement gRPC session creator --- refs/types.go | 7 ++- service/types.go | 18 +++++-- session/create.go | 67 +++++++++++++++++++++++++++ session/create_test.go | 103 +++++++++++++++++++++++++++++++++++++++++ session/request.go | 4 ++ session/types.go | 25 ++++++++++ 6 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 session/create.go create mode 100644 session/create_test.go diff --git a/refs/types.go b/refs/types.go index a29424e..417eec3 100644 --- a/refs/types.go +++ b/refs/types.go @@ -37,9 +37,14 @@ type ( OwnerID chain.WalletAddress ) +// OwnerIDSource is an interface of the container of an OwnerID value with read access. +type OwnerIDSource interface { + GetOwnerID() OwnerID +} + // OwnerIDContainer is an interface of the container of an OwnerID value. type OwnerIDContainer interface { - GetOwnerID() OwnerID + OwnerIDSource SetOwnerID(OwnerID) } diff --git a/service/types.go b/service/types.go index c3148a0..52d68d2 100644 --- a/service/types.go +++ b/service/types.go @@ -124,6 +124,18 @@ type ExpirationEpochContainer interface { SetExpirationEpoch(uint64) } +// LifetimeSource is an interface of the container of creation-expiration epoch pair with read access. +type LifetimeSource interface { + CreationEpochSource + ExpirationEpochSource +} + +// LifetimeSource is an interface of the container of creation-expiration epoch pair. +type LifetimeContainer interface { + CreationEpochContainer + ExpirationEpochContainer +} + // SessionKeySource is an interface of the container of session key bytes with read access. type SessionKeySource interface { GetSessionKey() []byte @@ -157,16 +169,14 @@ type SessionTokenSource interface { // - ID of the token's owner; // - verb of the session; // - address of the session object; -// - creation epoch number of the token; -// - expiration epoch number of the token; +// - token lifetime; // - public session key bytes. type SessionTokenInfo interface { TokenIDContainer OwnerIDContainer VerbContainer AddressContainer - CreationEpochContainer - ExpirationEpochContainer + LifetimeContainer SessionKeyContainer } diff --git a/session/create.go b/session/create.go new file mode 100644 index 0000000..a2d2b99 --- /dev/null +++ b/session/create.go @@ -0,0 +1,67 @@ +package session + +import ( + "context" + "crypto/ecdsa" + + "github.com/nspcc-dev/neofs-api-go/internal" + "github.com/nspcc-dev/neofs-api-go/service" + crypto "github.com/nspcc-dev/neofs-crypto" + "google.golang.org/grpc" +) + +type gRPCCreator struct { + conn *grpc.ClientConn + + key *ecdsa.PrivateKey + + clientFunc func(*grpc.ClientConn) SessionClient +} + +const ErrNilCreateParamsSource = internal.Error("create params source is nil") + +const ErrNilGPRCClientConn = internal.Error("gRPC client connection is nil") + +// NewGRPCCreator unites virtual gRPC client with private ket and returns Creator interface. +// +// If passed ClientConn is nil, ErrNilGPRCClientConn returns. +// If passed private key is nil, crypto.ErrEmptyPrivateKey returns. +func NewGRPCCreator(conn *grpc.ClientConn, key *ecdsa.PrivateKey) (Creator, error) { + if conn == nil { + return nil, ErrNilGPRCClientConn + } else if key == nil { + return nil, crypto.ErrEmptyPrivateKey + } + + return &gRPCCreator{ + conn: conn, + + key: key, + + clientFunc: NewSessionClient, + }, nil +} + +// Create constructs message, signs it with private key and sends it to a gRPC client. +// +// If passed CreateParamsSource is nil, ErrNilCreateParamsSource returns. +// If message could not be signed, an error returns. +func (s gRPCCreator) Create(ctx context.Context, p CreateParamsSource) (CreateResult, error) { + if p == nil { + return nil, ErrNilCreateParamsSource + } + + // create and fill a message + req := new(CreateRequest) + req.SetOwnerID(p.GetOwnerID()) + req.SetCreationEpoch(p.CreationEpoch()) + req.SetExpirationEpoch(p.ExpirationEpoch()) + + // sign with private key + if err := service.SignDataWithSessionToken(s.key, req); err != nil { + return nil, err + } + + // make gRPC call + return s.clientFunc(s.conn).Create(ctx, req) +} diff --git a/session/create_test.go b/session/create_test.go new file mode 100644 index 0000000..732d4fd --- /dev/null +++ b/session/create_test.go @@ -0,0 +1,103 @@ +package session + +import ( + "context" + "crypto/ecdsa" + "testing" + + "github.com/nspcc-dev/neofs-api-go/service" + crypto "github.com/nspcc-dev/neofs-crypto" + "github.com/nspcc-dev/neofs-crypto/test" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" +) + +type testSessionClient struct { + fn func(*CreateRequest) + resp *CreateResponse + err error +} + +func (s testSessionClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + if s.fn != nil { + s.fn(in) + } + + return s.resp, s.err +} + +func TestNewGRPCCreator(t *testing.T) { + var ( + err error + conn = new(grpc.ClientConn) + sk = new(ecdsa.PrivateKey) + ) + + // nil client connection + _, err = NewGRPCCreator(nil, sk) + require.EqualError(t, err, ErrNilGPRCClientConn.Error()) + + // nil private key + _, err = NewGRPCCreator(conn, nil) + require.EqualError(t, err, crypto.ErrEmptyPrivateKey.Error()) + + // valid params + res, err := NewGRPCCreator(conn, sk) + require.NoError(t, err) + + v := res.(*gRPCCreator) + require.Equal(t, conn, v.conn) + require.Equal(t, sk, v.key) + require.NotNil(t, v.clientFunc) +} + +func TestGRPCCreator_Create(t *testing.T) { + ctx := context.TODO() + s := new(gRPCCreator) + + // nil CreateParamsSource + _, err := s.Create(ctx, nil) + require.EqualError(t, err, ErrNilCreateParamsSource.Error()) + + var ( + ownerID = OwnerID{1, 2, 3} + created = uint64(2) + expired = uint64(4) + ) + + p := NewParams() + p.SetOwnerID(ownerID) + p.SetCreationEpoch(created) + p.SetExpirationEpoch(expired) + + // nil private key + _, err = s.Create(ctx, p) + require.Error(t, err) + + // create test private key + s.key = test.DecodeKey(0) + + // create test client + c := &testSessionClient{ + fn: func(req *CreateRequest) { + require.Equal(t, ownerID, req.GetOwnerID()) + require.Equal(t, created, req.CreationEpoch()) + require.Equal(t, expired, req.ExpirationEpoch()) + require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(req)) + }, + resp: &CreateResponse{ + ID: TokenID{1, 2, 3}, + SessionKey: []byte{1, 2, 3}, + }, + err: errors.New("test error"), + } + + s.clientFunc = func(*grpc.ClientConn) SessionClient { + return c + } + + res, err := s.Create(ctx, p) + require.EqualError(t, err, c.err.Error()) + require.Equal(t, c.resp, res) +} diff --git a/session/request.go b/session/request.go index 85f563f..161edca 100644 --- a/session/request.go +++ b/session/request.go @@ -14,6 +14,10 @@ const signedRequestDataSize = 0 + var requestEndianness = binary.BigEndian +func NewParams() CreateParamsContainer { + return new(CreateRequest) +} + // GetOwnerID is an OwnerID field getter. func (m CreateRequest) GetOwnerID() OwnerID { return m.OwnerID diff --git a/session/types.go b/session/types.go index c890aaf..9e8db48 100644 --- a/session/types.go +++ b/session/types.go @@ -5,6 +5,8 @@ import ( "crypto/ecdsa" "github.com/nspcc-dev/neofs-api-go/internal" + "github.com/nspcc-dev/neofs-api-go/refs" + "github.com/nspcc-dev/neofs-api-go/service" ) // PrivateToken is an interface of session private part. @@ -55,5 +57,28 @@ type KeyStore interface { Get(context.Context, OwnerID) ([]*ecdsa.PublicKey, error) } +// CreateParamsSource is an interface of the container of session parameters with read access. +type CreateParamsSource interface { + refs.OwnerIDSource + service.LifetimeSource +} + +// CreateParamsContainer is an interface of the container of session parameters. +type CreateParamsContainer interface { + refs.OwnerIDContainer + service.LifetimeContainer +} + +// CreateResult is an interface of the container of an opened session info with read access. +type CreateResult interface { + service.TokenIDSource + service.SessionKeySource +} + +// Creator is an interface of the tool for a session opening. +type Creator interface { + Create(context.Context, CreateParamsSource) (CreateResult, error) +} + // ErrPrivateTokenNotFound is raised when addressed private token was not found in storage. const ErrPrivateTokenNotFound = internal.Error("private token not found") From 2c2150b1017c8368c20b0110215a67dd9b329d75 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 8 May 2020 12:37:56 +0300 Subject: [PATCH 5/6] session: move errors to a separate file --- session/create.go | 5 ----- session/errors.go | 15 +++++++++++++++ session/types.go | 4 ---- 3 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 session/errors.go diff --git a/session/create.go b/session/create.go index a2d2b99..35d0540 100644 --- a/session/create.go +++ b/session/create.go @@ -4,7 +4,6 @@ import ( "context" "crypto/ecdsa" - "github.com/nspcc-dev/neofs-api-go/internal" "github.com/nspcc-dev/neofs-api-go/service" crypto "github.com/nspcc-dev/neofs-crypto" "google.golang.org/grpc" @@ -18,10 +17,6 @@ type gRPCCreator struct { clientFunc func(*grpc.ClientConn) SessionClient } -const ErrNilCreateParamsSource = internal.Error("create params source is nil") - -const ErrNilGPRCClientConn = internal.Error("gRPC client connection is nil") - // NewGRPCCreator unites virtual gRPC client with private ket and returns Creator interface. // // If passed ClientConn is nil, ErrNilGPRCClientConn returns. diff --git a/session/errors.go b/session/errors.go new file mode 100644 index 0000000..3a9c129 --- /dev/null +++ b/session/errors.go @@ -0,0 +1,15 @@ +package session + +import "github.com/nspcc-dev/neofs-api-go/internal" + +// ErrNilCreateParamsSource is returned by functions that expect a non-nil +// CreateParamsSource, but received nil. +const ErrNilCreateParamsSource = internal.Error("create params source is nil") + +// ErrNilGPRCClientConn is returned by functions that expect a non-nil +// grpc.ClientConn, but received nil. +const ErrNilGPRCClientConn = internal.Error("gRPC client connection is nil") + +// ErrPrivateTokenNotFound is returned when addressed private token was +// not found in storage. +const ErrPrivateTokenNotFound = internal.Error("private token not found") diff --git a/session/types.go b/session/types.go index 9e8db48..932fe38 100644 --- a/session/types.go +++ b/session/types.go @@ -4,7 +4,6 @@ import ( "context" "crypto/ecdsa" - "github.com/nspcc-dev/neofs-api-go/internal" "github.com/nspcc-dev/neofs-api-go/refs" "github.com/nspcc-dev/neofs-api-go/service" ) @@ -79,6 +78,3 @@ type CreateResult interface { type Creator interface { Create(context.Context, CreateParamsSource) (CreateResult, error) } - -// ErrPrivateTokenNotFound is raised when addressed private token was not found in storage. -const ErrPrivateTokenNotFound = internal.Error("private token not found") From 15a55d54a22a21ff6e044754937d87222754ad85 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 8 May 2020 12:45:16 +0300 Subject: [PATCH 6/6] fix comments --- service/types.go | 2 +- session/request.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/service/types.go b/service/types.go index 52d68d2..31f4507 100644 --- a/service/types.go +++ b/service/types.go @@ -130,7 +130,7 @@ type LifetimeSource interface { ExpirationEpochSource } -// LifetimeSource is an interface of the container of creation-expiration epoch pair. +// LifetimeContainer is an interface of the container of creation-expiration epoch pair. type LifetimeContainer interface { CreationEpochContainer ExpirationEpochContainer diff --git a/session/request.go b/session/request.go index 161edca..0bb5176 100644 --- a/session/request.go +++ b/session/request.go @@ -14,6 +14,7 @@ const signedRequestDataSize = 0 + var requestEndianness = binary.BigEndian +// NewParams creates a new CreateRequest message and returns CreateParamsContainer interface. func NewParams() CreateParamsContainer { return new(CreateRequest) } @@ -28,6 +29,7 @@ func (m *CreateRequest) SetOwnerID(id OwnerID) { m.OwnerID = id } +// SignedData returns payload bytes of the request. func (m CreateRequest) SignedData() ([]byte, error) { data := make([]byte, m.SignedDataSize()) @@ -39,10 +41,14 @@ func (m CreateRequest) SignedData() ([]byte, error) { return data, nil } +// SignedDataSize returns payload size of the request. func (m CreateRequest) SignedDataSize() int { return signedRequestDataSize } +// ReadSignedData copies payload bytes to passed buffer. +// +// If the buffer size is insufficient, io.ErrUnexpectedEOF returns. func (m CreateRequest) ReadSignedData(p []byte) (int, error) { sz := m.SignedDataSize() if len(p) < sz {