Compare commits

...

12 commits

Author SHA1 Message Date
cd2e46a17c [#10] Add __FROSTFS__ system attributes
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-13 09:59:22 +03:00
c46cd37f71 [#10] Generate api
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-13 09:59:22 +03:00
ec0d0274fa [#3] signature: Add buffer pool
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-03-10 13:36:26 +03:00
73fde0e37c [#3] signature: Verify parts in parallel
Verify request/response parts in parallel

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-03-10 13:36:26 +03:00
611f73ad0f [#3] signature: Sign parts in parallel
Sign request/response parts in parallel

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-03-10 13:36:26 +03:00
e073c996fc [#3] signature: Add benchmarks
Add benchmarks for sign and verify methods

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-03-10 13:36:26 +03:00
d005bf0393 [#3] signature: Refactor sign and verify
Split methods to separate files, drop redundant intefaces

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-03-10 13:36:26 +03:00
63eb4dc3ea [#3] api-go: Go version up
Update go version 1.17 -> 1.18

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-03-10 13:36:26 +03:00
3f7cb1b5ef [#7] .github: Remove directory
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 19:47:04 +00:00
bd67469f43 [#7] pre-commit: Add gitlint hook
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 19:47:04 +00:00
3af7645abf [#7] pre-commit: Add golangci-lint hook
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 19:47:04 +00:00
5faee63f60 [#7] pre-commit: Add initial configuration
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 19:47:04 +00:00
31 changed files with 603 additions and 587 deletions

70
.github/logo.svg vendored
View file

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 184.2 51.8" style="enable-background:new 0 0 184.2 51.8;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;}
.st2{fill:#01E397;}
.st3{display:inline;fill:#010032;}
.st4{display:inline;fill:#00E599;}
.st5{display:inline;fill:#00AF92;}
.st6{fill:#00C3E5;}
</style>
<g id="Layer_2">
<g id="Layer_1-2" class="st0">
<g class="st1">
<path class="st2" d="M146.6,18.3v7.2h10.9V29h-10.9v10.7h-4V14.8h18v3.5H146.6z"/>
<path class="st2" d="M180,15.7c1.7,0.9,3,2.2,4,3.8l-3,2.7c-0.6-1.3-1.5-2.4-2.6-3.3c-1.3-0.7-2.8-1-4.3-1
c-1.4-0.1-2.8,0.3-4,1.1c-0.9,0.5-1.5,1.5-1.4,2.6c0,1,0.5,1.9,1.4,2.4c1.5,0.8,3.2,1.3,4.9,1.5c1.9,0.3,3.7,0.8,5.4,1.6
c1.2,0.5,2.2,1.3,2.9,2.3c0.6,1,1,2.2,0.9,3.4c0,1.4-0.5,2.7-1.3,3.8c-0.9,1.2-2.1,2.1-3.5,2.6c-1.7,0.6-3.4,0.9-5.2,0.8
c-5,0-8.6-1.6-10.7-5l2.9-2.8c0.7,1.4,1.8,2.5,3.1,3.3c1.5,0.7,3.1,1.1,4.7,1c1.5,0.1,2.9-0.2,4.2-0.9c0.9-0.5,1.5-1.5,1.5-2.6
c0-0.9-0.5-1.8-1.3-2.2c-1.5-0.7-3.1-1.2-4.8-1.5c-1.9-0.3-3.7-0.8-5.5-1.5c-1.2-0.5-2.2-1.4-3-2.4c-0.6-1-1-2.2-0.9-3.4
c0-1.4,0.4-2.7,1.2-3.8c0.8-1.2,2-2.2,3.3-2.8c1.6-0.7,3.4-1.1,5.2-1C176.1,14.3,178.2,14.8,180,15.7z"/>
</g>
<path class="st3" d="M73.3,16.3c1.9,1.9,2.9,4.5,2.7,7.1v15.9h-4V24.8c0-2.6-0.5-4.5-1.6-5.7c-1.2-1.2-2.8-1.8-4.5-1.7
c-1.3,0-2.5,0.3-3.7,0.8c-1.2,0.7-2.2,1.7-2.9,2.9c-0.8,1.5-1.1,3.2-1.1,4.9v13.3h-4V15.1l3.6,1.5v1.7c0.8-1.5,2.1-2.6,3.6-3.3
c1.5-0.8,3.2-1.2,4.9-1.1C68.9,13.8,71.3,14.7,73.3,16.3z"/>
<path class="st3" d="M104.4,28.3H85.6c0.1,2.2,1,4.3,2.5,5.9c1.5,1.4,3.5,2.2,5.6,2.1c1.6,0.1,3.2-0.2,4.6-0.9
c1.1-0.6,2-1.6,2.5-2.8l3.3,1.8c-0.9,1.7-2.3,3.1-4,4c-2,1-4.2,1.5-6.4,1.4c-3.7,0-6.7-1.1-8.8-3.4s-3.2-5.5-3.2-9.6s1-7.2,3-9.5
s5-3.4,8.7-3.4c2.1-0.1,4.2,0.5,6.1,1.5c1.6,1,3,2.5,3.8,4.2c0.9,1.8,1.3,3.9,1.3,5.9C104.6,26.4,104.6,27.4,104.4,28.3z
M88.1,19.3c-1.4,1.5-2.2,3.4-2.4,5.5h15.1c-0.2-2-1-3.9-2.3-5.5c-1.4-1.3-3.2-2-5.1-1.9C91.5,17.3,89.6,18,88.1,19.3z"/>
<path class="st3" d="M131,17.3c2.2,2.3,3.2,5.5,3.2,9.5s-1,7.3-3.2,9.6s-5.1,3.4-8.8,3.4s-6.7-1.1-8.9-3.4s-3.2-5.5-3.2-9.6
s1.1-7.2,3.2-9.5s5.1-3.4,8.9-3.4S128.9,15,131,17.3z M116.2,19.9c-1.5,2-2.2,4.4-2.1,6.9c-0.2,2.5,0.6,5,2.1,7
c1.5,1.7,3.7,2.7,6,2.6c2.3,0.1,4.4-0.9,5.9-2.6c1.5-2,2.3-4.5,2.1-7c0.1-2.5-0.6-4.9-2.1-6.9c-1.5-1.7-3.6-2.7-5.9-2.6
C119.9,17.2,117.7,18.2,116.2,19.9z"/>
<polygon class="st4" points="0,9.1 0,43.7 22.5,51.8 22.5,16.9 46.8,7.9 24.8,0 "/>
<polygon class="st5" points="24.3,17.9 24.3,36.8 46.8,44.9 46.8,9.6 "/>
</g>
<g>
<g>
<path class="st6" d="M41.6,17.5H28.2v6.9h10.4v3.3H28.2v10.2h-3.9V14.2h17.2V17.5z"/>
<path class="st6" d="M45.8,37.9v-18h3.3l0.4,3.2c0.5-1.2,1.2-2.1,2.1-2.7c0.9-0.6,2.1-0.9,3.5-0.9c0.4,0,0.7,0,1.1,0.1
c0.4,0.1,0.7,0.2,0.9,0.3l-0.5,3.4c-0.3-0.1-0.6-0.2-0.9-0.2C55.4,23,54.9,23,54.4,23c-0.7,0-1.5,0.2-2.2,0.6
c-0.7,0.4-1.3,1-1.8,1.8s-0.7,1.8-0.7,3v9.5H45.8z"/>
<path class="st6" d="M68.6,19.6c1.8,0,3.3,0.4,4.6,1.1c1.3,0.7,2.4,1.8,3.1,3.2s1.1,3.1,1.1,5c0,1.9-0.4,3.6-1.1,5
c-0.8,1.4-1.8,2.5-3.1,3.2c-1.3,0.7-2.9,1.1-4.6,1.1s-3.3-0.4-4.6-1.1c-1.3-0.7-2.4-1.8-3.2-3.2c-0.8-1.4-1.2-3.1-1.2-5
c0-1.9,0.4-3.6,1.2-5s1.8-2.5,3.2-3.2C65.3,19.9,66.8,19.6,68.6,19.6z M68.6,22.6c-1.1,0-2,0.2-2.8,0.7c-0.8,0.5-1.3,1.2-1.7,2.1
s-0.6,2.1-0.6,3.5c0,1.3,0.2,2.5,0.6,3.4s1,1.7,1.7,2.2s1.7,0.7,2.8,0.7c1.1,0,2-0.2,2.7-0.7c0.7-0.5,1.3-1.2,1.7-2.2
s0.6-2.1,0.6-3.4c0-1.4-0.2-2.5-0.6-3.5s-1-1.6-1.7-2.1C70.6,22.8,69.6,22.6,68.6,22.6z"/>
<path class="st6" d="M89.2,38.3c-1.8,0-3.4-0.3-4.9-1c-1.5-0.7-2.7-1.7-3.5-3l2.7-2.3c0.5,1,1.3,1.8,2.3,2.4
c1,0.6,2.2,0.9,3.6,0.9c1.1,0,2-0.2,2.6-0.6c0.6-0.4,1-0.9,1-1.6c0-0.5-0.2-0.9-0.5-1.2s-0.9-0.6-1.7-0.8l-3.8-0.8
c-1.9-0.4-3.3-1-4.1-1.9c-0.8-0.9-1.2-1.9-1.2-3.3c0-1,0.3-1.9,0.9-2.7c0.6-0.8,1.4-1.5,2.5-2s2.5-0.8,4-0.8c1.8,0,3.3,0.3,4.6,1
c1.3,0.6,2.2,1.5,2.9,2.7l-2.7,2.2c-0.5-1-1.1-1.7-2-2.1c-0.9-0.5-1.8-0.7-2.8-0.7c-0.8,0-1.4,0.1-2,0.3c-0.6,0.2-1,0.5-1.3,0.8
c-0.3,0.3-0.4,0.7-0.4,1.2c0,0.5,0.2,0.9,0.5,1.3s1,0.6,1.9,0.8l4.1,0.9c1.7,0.3,2.9,0.9,3.7,1.7c0.7,0.8,1.1,1.8,1.1,2.9
c0,1.2-0.3,2.2-0.9,3c-0.6,0.9-1.5,1.6-2.6,2C92.1,38.1,90.7,38.3,89.2,38.3z"/>
<path class="st6" d="M112.8,19.9v3H99.3v-3H112.8z M106.6,14.6v17.9c0,0.9,0.2,1.5,0.7,1.9c0.5,0.4,1.1,0.6,1.9,0.6
c0.6,0,1.2-0.1,1.7-0.3c0.5-0.2,0.9-0.5,1.3-0.8l0.9,2.8c-0.6,0.5-1.2,0.9-2,1.1c-0.8,0.3-1.7,0.4-2.7,0.4c-1,0-2-0.2-2.8-0.5
s-1.5-0.9-2-1.6c-0.5-0.8-0.7-1.7-0.8-3V15.7L106.6,14.6z"/>
<path d="M137.9,17.5h-13.3v6.9h10.4v3.3h-10.4v10.2h-3.9V14.2h17.2V17.5z"/>
<path d="M150.9,13.8c2.1,0,4,0.4,5.5,1.2c1.6,0.8,2.9,2,4,3.5l-2.6,2.5c-0.9-1.4-1.9-2.4-3.1-3c-1.1-0.6-2.5-0.9-4-0.9
c-1.2,0-2.1,0.2-2.8,0.5c-0.7,0.3-1.3,0.7-1.6,1.2c-0.3,0.5-0.5,1.1-0.5,1.7c0,0.7,0.3,1.4,0.8,1.9c0.5,0.6,1.5,1,2.9,1.3
l4.8,1.1c2.3,0.5,3.9,1.3,4.9,2.3c1,1,1.4,2.3,1.4,3.9c0,1.5-0.4,2.7-1.2,3.8c-0.8,1.1-1.9,1.9-3.3,2.5s-3.1,0.9-5,0.9
c-1.7,0-3.2-0.2-4.5-0.6c-1.3-0.4-2.5-1-3.5-1.8c-1-0.7-1.8-1.6-2.5-2.6l2.7-2.7c0.5,0.8,1.1,1.6,1.9,2.2
c0.8,0.7,1.7,1.2,2.7,1.5c1,0.4,2.2,0.5,3.4,0.5c1.1,0,2.1-0.1,2.9-0.4c0.8-0.3,1.4-0.7,1.8-1.2c0.4-0.5,0.6-1.1,0.6-1.9
c0-0.7-0.2-1.3-0.7-1.8c-0.5-0.5-1.3-0.9-2.6-1.2l-5.2-1.2c-1.4-0.3-2.6-0.8-3.6-1.3c-0.9-0.6-1.6-1.3-2.1-2.1s-0.7-1.8-0.7-2.8
c0-1.3,0.4-2.6,1.1-3.7c0.7-1.1,1.8-2,3.2-2.6C147.3,14.1,148.9,13.8,150.9,13.8z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -1,21 +0,0 @@
name: DCO check
on:
pull_request:
branches:
- master
jobs:
commits_check_job:
runs-on: ubuntu-latest
name: Commits Check
steps:
- name: Get PR Commits
id: 'get-pr-commits'
uses: tim-actions/get-pr-commits@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: DCO Check
uses: tim-actions/dco@master
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}

View file

@ -1,64 +0,0 @@
name: neofs-api-go tests
on:
push:
branches:
- master
paths-ignore:
- '*.md'
pull_request:
branches:
- master
paths-ignore:
- '*.md'
jobs:
test:
runs-on: ubuntu-20.04
strategy:
matrix:
go: [ '1.17.x', '1.18.x', '1.19.x' ]
steps:
- name: Setup go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Check out code
uses: actions/checkout@v3
- name: Cache go mod
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go }}-
- name: Get dependencies
run: make dep
- name: Run go test
run: go test -coverprofile=coverage.txt -covermode=atomic ./...
- name: Codecov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: bash <(curl -s https://codecov.io/bash)
lint:
runs-on: ubuntu-20.04
steps:
- name: Setup go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Check out code
uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.48.0
only-new-issues: true

10
.gitlint Normal file
View file

@ -0,0 +1,10 @@
[general]
fail-without-commits=true
contrib=CC1
[title-match-regex]
regex=^\[\#[0-9]+\]\s
[ignore-by-title]
regex=^Release(.*)
ignore=title-match-regex

View file

@ -11,7 +11,7 @@ run:
skip-files: skip-files:
- (^|.*/)grpc/(.*) - (^|.*/)grpc/(.*)
# output configuration options # output configuration options
output: output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
@ -64,4 +64,4 @@ issues:
- linters: # ignore SA6002 since we use pool of []byte, however we can switch to *bytes.Buffer - linters: # ignore SA6002 since we use pool of []byte, however we can switch to *bytes.Buffer
- staticcheck - staticcheck
text: "SA6002:" text: "SA6002:"

30
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,30 @@
ci:
autofix_prs: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- id: check-merge-conflict
- id: check-json
- id: check-xml
- id: check-yaml
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- id: end-of-file-fixer
exclude: ".key$"
- repo: https://github.com/golangci/golangci-lint
rev: v1.51.2
hooks:
- id: golangci-lint
- repo: https://github.com/jorisroovers/gitlint
rev: v0.18.0
hooks:
- id: gitlint
stages: [commit-msg]

View file

@ -22,7 +22,7 @@
- Mark all expiration methods as deprecated (#417) - Mark all expiration methods as deprecated (#417)
### Updated ### Updated
- Minimal go version to 1.17 (#412) - Minimal go version to 1.17 (#412)
- `neofs-crypto` to `v0.4.0` (#412) - `neofs-crypto` to `v0.4.0` (#412)
- `google.golang.org/grpc` to `v1.48.0` (#415) - `google.golang.org/grpc` to `v1.48.0` (#415)
- `google.golang.org/protobuf` to `v1.28.0` (#415) - `google.golang.org/protobuf` to `v1.28.0` (#415)
@ -60,7 +60,7 @@ NeoFS API v2.13 support
### Fixed ### Fixed
- Incompatible changes in signature scheme (#380) - Incompatible changes in signature scheme (#380)
### Added ### Added
- Public URI-parsing function `client.ParseURI()` (#383) - Public URI-parsing function `client.ParseURI()` (#383)
@ -92,9 +92,9 @@ NeoFS API v2.12 support
## [2.11.0] - 2021-12-02 - Sinjido (신지도, 薪智島) ## [2.11.0] - 2021-12-02 - Sinjido (신지도, 薪智島)
NeoFS API v2.11 support. High level packages are moved to NeoFS API v2.11 support. High level packages are moved to
[neofs-sdk-go](https://github.com/nspcc-dev/neofs-sdk-go) repository. [neofs-sdk-go](https://github.com/nspcc-dev/neofs-sdk-go) repository.
Repository restructured as Go module version 2 and synced with Repository restructured as Go module version 2 and synced with
[neofs-api](https://github.com/nspcc-dev/neofs-api) release version. [neofs-api](https://github.com/nspcc-dev/neofs-api) release version.
### Fixed ### Fixed
@ -109,7 +109,7 @@ Repository restructured as Go module version 2 and synced with
- neofs-api-go is now Go module version 2 (#201) - neofs-api-go is now Go module version 2 (#201)
### Removed ### Removed
- All packages from `pkg` moved to - All packages from `pkg` moved to
[neofs-sdk-go](https://github.com/nspcc-dev/neofs-sdk-go) (#201) [neofs-sdk-go](https://github.com/nspcc-dev/neofs-sdk-go) (#201)
## [1.30.0] - 2021-10-19 - Udo (우도, 牛島) ## [1.30.0] - 2021-10-19 - Udo (우도, 牛島)
@ -126,7 +126,7 @@ NeoFS API v2.10 support.
- pkg/client callback to parse internal response information (#337) - pkg/client callback to parse internal response information (#337)
- Service filter type in extended ACL from API v2.10 (#338) - Service filter type in extended ACL from API v2.10 (#338)
- Enhanced network info structures from API v2.10 (#339) - Enhanced network info structures from API v2.10 (#339)
- Well-known public-append basic ACL constant (#341) - Well-known public-append basic ACL constant (#341)
- Native contract names support (#351) - Native contract names support (#351)
### Changed ### Changed
@ -258,7 +258,7 @@ Raw client and support of NeoFS API v2.5.0 "Jebudo" release.
### Added ### Added
- Raw client for peer to peer communication. - Raw client for peer to peer communication.
- `client.WithKey` option to sign messages with different keys within single - `client.WithKey` option to sign messages with different keys within single
client. client.
- `Content-Type` well-known object attribute constant. - `Content-Type` well-known object attribute constant.
@ -271,7 +271,7 @@ Raw client and support of NeoFS API v2.5.0 "Jebudo" release.
Support changes from NeoFS API v2.4.0 "Ganghwado" release. Support changes from NeoFS API v2.4.0 "Ganghwado" release.
### Added ### Added
- `netmap.NetworkInfo` definitions in `v2` and `pkg/netmap`. - `netmap.NetworkInfo` definitions in `v2` and `pkg/netmap`.
- `netmap.NetworkInfo` RPC support in `pkg/client`. - `netmap.NetworkInfo` RPC support in `pkg/client`.
@ -322,7 +322,7 @@ Support changes from NeoFS API v2.2.1 release.
### Fixed ### Fixed
- Remarks of the updated linter. - Remarks of the updated linter.
## [1.22.0] - 2020-12-30 - Yeouido (여의도, 汝矣島) ## [1.22.0] - 2020-12-30 - Yeouido (여의도, 汝矣島)
@ -335,7 +335,7 @@ Support changes from NeoFS API v2.2.0 "Yeouido" release.
- Support of `StorageGroup` message. - Support of `StorageGroup` message.
- Support of `DataAuditResult` message. - Support of `DataAuditResult` message.
- Stringer and string parser for `Checksum` type of client library. - Stringer and string parser for `Checksum` type of client library.
- Stringer and string parser for `Type` message. - Stringer and string parser for `Type` message.
- Stringer and string parser for `Type` type of client library. - Stringer and string parser for `Type` type of client library.
- `AddTypeFilter` method on `SearchFilters` type of client library - `AddTypeFilter` method on `SearchFilters` type of client library
that adds filter by object type. that adds filter by object type.
@ -350,7 +350,7 @@ Support changes from NeoFS API v2.2.0 "Yeouido" release.
- `Container.SetNonceUUID` setter of container nonce in UUID format. - `Container.SetNonceUUID` setter of container nonce in UUID format.
- `NewVerifiedContainerFromV2` container constructor that preliminary - `NewVerifiedContainerFromV2` container constructor that preliminary
checks if container message argument meets NeoFS API V2 specification. checks if container message argument meets NeoFS API V2 specification.
### Changed ### Changed
- `Container.Nonce`/`Container.SetNonce` marked as deprecated. - `Container.Nonce`/`Container.SetNonce` marked as deprecated.
@ -368,7 +368,7 @@ Support neofs-api v2.1.1.
### Added ### Added
- `client.GetVerifiedContainerStructure` function to check - `client.GetVerifiedContainerStructure` function to check
that the container structure matches the requested identifier. that the container structure matches the requested identifier.
## [1.21.0] - 2020-12-11 - Modo (모도, 茅島) ## [1.21.0] - 2020-12-11 - Modo (모도, 茅島)
@ -391,7 +391,7 @@ Support neofs-api v2.1.1.
### Renamed ### Renamed
- `AddLeafFilter` to `AddPhyFilter` - `AddLeafFilter` to `AddPhyFilter`
### Fixed ### Fixed
@ -425,9 +425,9 @@ Support neofs-api v2.1.1.
## [1.20.0] - 2020-11-16 - Jindo (진도, 珍島) ## [1.20.0] - 2020-11-16 - Jindo (진도, 珍島)
Major API refactoring and simplification. From now on this library will have Major API refactoring and simplification. From now on this library will have
backward compatibility and support of major versions of NeoFS-API by having backward compatibility and support of major versions of NeoFS-API by having
**version specific** files in `vN` dirs and **version independent** SDK **version specific** files in `vN` dirs and **version independent** SDK
structures and client in `pkg`. This version supports NeoFS-API v2.0.X structures and client in `pkg`. This version supports NeoFS-API v2.0.X

0
Makefile Normal file → Executable file
View file

View file

@ -1,7 +1,7 @@
package container package container
// SysAttributePrefix is a prefix of key to system attribute. // SysAttributePrefix is a prefix of key to system attribute.
const SysAttributePrefix = "__NEOFS__" const SysAttributePrefix = "__FROSTFS__"
const ( const (
// SysAttributeSubnet is a string ID of container's storage subnet. // SysAttributeSubnet is a string ID of container's storage subnet.
@ -17,6 +17,23 @@ const (
SysAttributeHomomorphicHashing = SysAttributePrefix + "DISABLE_HOMOMORPHIC_HASHING" SysAttributeHomomorphicHashing = SysAttributePrefix + "DISABLE_HOMOMORPHIC_HASHING"
) )
// SysAttributePrefixNeoFS is a prefix of key to system attribute.
const SysAttributePrefixNeoFS = "__NEOFS__"
const (
// SysAttributeSubnetNeoFS is a string ID of container's storage subnet.
SysAttributeSubnetNeoFS = SysAttributePrefixNeoFS + "SUBNET"
// SysAttributeNameNeoFS is a string of human-friendly container name registered as the domain in NNS contract.
SysAttributeNameNeoFS = SysAttributePrefixNeoFS + "NAME"
// SysAttributeZoneNeoFS is a string of zone for container name.
SysAttributeZoneNeoFS = SysAttributePrefixNeoFS + "ZONE"
// SysAttributeHomomorphicHashingNeoFS is a container's homomorphic hashing state.
SysAttributeHomomorphicHashingNeoFS = SysAttributePrefixNeoFS + "DISABLE_HOMOMORPHIC_HASHING"
)
// SysAttributeZoneDefault is a default value for SysAttributeZone attribute. // SysAttributeZoneDefault is a default value for SysAttributeZone attribute.
const SysAttributeZoneDefault = "container" const SysAttributeZoneDefault = "container"
@ -33,7 +50,7 @@ const disabledHomomorphicHashingValue = "true"
// See also SetHomomorphicHashingState. // See also SetHomomorphicHashingState.
func (c Container) HomomorphicHashingState() bool { func (c Container) HomomorphicHashingState() bool {
for i := range c.attr { for i := range c.attr {
if c.attr[i].GetKey() == SysAttributeHomomorphicHashing { if c.attr[i].GetKey() == SysAttributeHomomorphicHashing || c.attr[i].GetKey() == SysAttributeHomomorphicHashingNeoFS {
return c.attr[i].GetValue() != disabledHomomorphicHashingValue return c.attr[i].GetValue() != disabledHomomorphicHashingValue
} }
} }
@ -50,7 +67,7 @@ func (c Container) HomomorphicHashingState() bool {
// See also HomomorphicHashingState. // See also HomomorphicHashingState.
func (c *Container) SetHomomorphicHashingState(enable bool) { func (c *Container) SetHomomorphicHashingState(enable bool) {
for i := range c.attr { for i := range c.attr {
if c.attr[i].GetKey() == SysAttributeHomomorphicHashing { if c.attr[i].GetKey() == SysAttributeHomomorphicHashing || c.attr[i].GetKey() == SysAttributeHomomorphicHashingNeoFS {
if enable { if enable {
// approach without allocation/waste // approach without allocation/waste
// coping works since the attributes // coping works since the attributes

View file

@ -131,16 +131,16 @@ func (x *Container) GetPlacementPolicy() *grpc1.PlacementPolicy {
// //
// There are some "well-known" attributes affecting system behaviour: // There are some "well-known" attributes affecting system behaviour:
// //
// - __NEOFS__SUBNET \ // - [ __NEOFS__SUBNET | __FROSTFS__SUBNET ] \
// String ID of a container's storage subnet. Any container can be attached to // String ID of a container's storage subnet. Any container can be attached to
// one subnet only. // one subnet only.
// - __NEOFS__NAME \ // - [ __NEOFS__NAME | __FROSTFS__NAME ] \
// String of a human-friendly container name registered as a domain in // String of a human-friendly container name registered as a domain in
// NNS contract. // NNS contract.
// - __NEOFS__ZONE \ // - [ __NEOFS__ZONE | __FROSTFS__ZONE ] \
// String of a zone for `__NEOFS__NAME`. Used as a TLD of a domain name in NNS // String of a zone for `__NEOFS__NAME`/`__FROSTFS__NAME`. Used as a TLD of a domain name in NNS
// contract. If no zone is specified, use default zone: `container`. // contract. If no zone is specified, use default zone: `container`.
// - __NEOFS__DISABLE_HOMOMORPHIC_HASHING \ // - [ __NEOFS__DISABLE_HOMOMORPHIC_HASHING | __FROSTFS__DISABLE_HOMOMORPHIC_HASHING ] \
// Disables homomorphic hashing for the container if the value equals "true" string. // Disables homomorphic hashing for the container if the value equals "true" string.
// Any other values are interpreted as missing attribute. Container could be // Any other values are interpreted as missing attribute. Container could be
// accepted in a NeoFS network only if the global network hashing configuration // accepted in a NeoFS network only if the global network hashing configuration

6
go.mod
View file

@ -1,10 +1,11 @@
module git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 module git.frostfs.info/TrueCloudLab/frostfs-api-go/v2
go 1.17 go 1.18
require ( require (
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/sync v0.1.0
google.golang.org/grpc v1.48.0 google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.0 google.golang.org/protobuf v1.28.0
) )
@ -13,10 +14,11 @@ require (
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect
github.com/davecgh/go-spew v1.1.0 // indirect github.com/davecgh/go-spew v1.1.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect golang.org/x/sys v0.1.0 // indirect
golang.org/x/text v0.3.3 // indirect golang.org/x/text v0.3.3 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect

9
go.sum
View file

@ -46,8 +46,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
@ -82,13 +83,16 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -98,7 +102,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

2
lock/grpc/types.pb.go generated
View file

@ -23,7 +23,7 @@ const (
// Lock objects protects a list of objects from being deleted. The lifetime of a // Lock objects protects a list of objects from being deleted. The lifetime of a
// lock object is limited similar to regular objects in // lock object is limited similar to regular objects in
// `__NEOFS__EXPIRATION_EPOCH` attribute. Lock object MUST have expiration epoch. // `__NEOFS__EXPIRATION_EPOCH`/`__FROSTFS__EXPIRATION_EPOCH` attribute. Lock object MUST have expiration epoch.
// It is impossible to delete a lock object via ObjectService.Delete RPC call. // It is impossible to delete a lock object via ObjectService.Delete RPC call.
type Lock struct { type Lock struct {
state protoimpl.MessageState state protoimpl.MessageState

View file

@ -9,7 +9,10 @@ import (
) )
// prefix of keys to subnet attributes. // prefix of keys to subnet attributes.
const attrSubnetPrefix = "__NEOFS__SUBNET_" const attrSubnetPrefix = "__FROSTFS__SUBNET_"
// prefix of keys to subnet attributes.
const attrSubnetPrefixNeoFS = "__NEOFS__SUBNET_"
const ( const (
// subnet attribute's value denoting subnet entry // subnet attribute's value denoting subnet entry
@ -62,7 +65,7 @@ func subnetAttributeKey(id *refs.SubnetID) string {
// - disables non-zero subnet; // - disables non-zero subnet;
// - enables zero subnet. // - enables zero subnet.
// //
// Attribute key is calculated from ID using format `__NEOFS__SUBNET_%s`. // Attribute key is calculated from ID using format `__FROSTFS__SUBNET_%s`.
// Attribute Value is: // Attribute Value is:
// - `True` if node enters the subnet; // - `True` if node enters the subnet;
// - `False`, otherwise. // - `False`, otherwise.
@ -143,8 +146,11 @@ func IterateSubnets(node *NodeInfo, f func(refs.SubnetID) error) error {
// cut subnet ID string // cut subnet ID string
idTxt := strings.TrimPrefix(key, attrSubnetPrefix) idTxt := strings.TrimPrefix(key, attrSubnetPrefix)
if len(idTxt) == len(key) { if len(idTxt) == len(key) {
// not a subnet attribute idTxt = strings.TrimPrefix(key, attrSubnetPrefixNeoFS)
continue if len(idTxt) == len(key) {
// not a subnet attribute
continue
}
} }
// check value // check value

View file

@ -11,7 +11,7 @@ import (
) )
func subnetAttrKey(val string) string { func subnetAttrKey(val string) string {
return "__NEOFS__SUBNET_" + val return "__FROSTFS__SUBNET_" + val
} }
func assertSubnetAttrKey(t *testing.T, attr *netmap.Attribute, num uint32) { func assertSubnetAttrKey(t *testing.T, attr *netmap.Attribute, num uint32) {

View file

@ -827,7 +827,7 @@ func (x *NetworkInfo) GetNetworkConfig() *NetworkConfig {
// attributes it's a string presenting floating point number with comma or // attributes it's a string presenting floating point number with comma or
// point delimiter for decimal part. In the Network Map it will be saved as // point delimiter for decimal part. In the Network Map it will be saved as
// 64-bit unsigned integer representing number of minimal token fractions. // 64-bit unsigned integer representing number of minimal token fractions.
// - __NEOFS__SUBNET_%s \ // - [ __NEOFS__SUBNET_%s | __FROSTFS__SUBNET_%s ] \
// `True` or `False`. Defines if the node is included in the `%s` subnetwork // `True` or `False`. Defines if the node is included in the `%s` subnetwork
// or not. `%s` must be an existing subnetwork's ID (non-negative integer number). // or not. `%s` must be an existing subnetwork's ID (non-negative integer number).
// A node can be included in more than one subnetwork and, therefore, can contain // A node can be included in more than one subnetwork and, therefore, can contain

View file

@ -7,7 +7,7 @@ import (
) )
// SysAttributePrefix is a prefix of key to system attribute. // SysAttributePrefix is a prefix of key to system attribute.
const SysAttributePrefix = "__NEOFS__" const SysAttributePrefix = "__FROSTFS__"
const ( const (
// SysAttributeUploadID marks smaller parts of a split bigger object. // SysAttributeUploadID marks smaller parts of a split bigger object.
@ -25,6 +25,25 @@ const (
SysAttributeTickTopic = SysAttributePrefix + "TICK_TOPIC" SysAttributeTickTopic = SysAttributePrefix + "TICK_TOPIC"
) )
// SysAttributePrefixNeoFS is a prefix of key to system attribute.
const SysAttributePrefixNeoFS = "__NEOFS__"
const (
// SysAttributeUploadIDNeoFS marks smaller parts of a split bigger object.
SysAttributeUploadIDNeoFS = SysAttributePrefixNeoFS + "UPLOAD_ID"
// SysAttributeExpEpochNeoFS tells GC to delete object after that epoch.
SysAttributeExpEpochNeoFS = SysAttributePrefixNeoFS + "EXPIRATION_EPOCH"
// SysAttributeTickEpochNeoFS defines what epoch must produce object
// notification.
SysAttributeTickEpochNeoFS = SysAttributePrefixNeoFS + "TICK_EPOCH"
// SysAttributeTickTopicNeoFS defines what topic object notification
// must be sent to.
SysAttributeTickTopicNeoFS = SysAttributePrefixNeoFS + "TICK_TOPIC"
)
// NotificationInfo groups information about object notification // NotificationInfo groups information about object notification
// that can be written to object. // that can be written to object.
// //
@ -81,10 +100,10 @@ func WriteNotificationInfo(o *Object, ni NotificationInfo) {
for i := range attrs { for i := range attrs {
switch attrs[i].GetKey() { switch attrs[i].GetKey() {
case SysAttributeTickEpoch: case SysAttributeTickEpoch, SysAttributeTickEpochNeoFS:
attrs[i].SetValue(epoch) attrs[i].SetValue(epoch)
changedEpoch = true changedEpoch = true
case SysAttributeTickTopic: case SysAttributeTickTopic, SysAttributeTickTopicNeoFS:
changedTopic = true changedTopic = true
if topic == "" { if topic == "" {
@ -141,7 +160,7 @@ func GetNotificationInfo(o *Object) (*NotificationInfo, error) {
for _, attr := range o.GetHeader().GetAttributes() { for _, attr := range o.GetHeader().GetAttributes() {
switch key := attr.GetKey(); key { switch key := attr.GetKey(); key {
case SysAttributeTickEpoch: case SysAttributeTickEpoch, SysAttributeTickEpochNeoFS:
epoch, err := strconv.ParseUint(attr.GetValue(), 10, 64) epoch, err := strconv.ParseUint(attr.GetValue(), 10, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not parse epoch: %w", err) return nil, fmt.Errorf("could not parse epoch: %w", err)
@ -150,7 +169,7 @@ func GetNotificationInfo(o *Object) (*NotificationInfo, error) {
ni.SetEpoch(epoch) ni.SetEpoch(epoch)
foundEpoch = true foundEpoch = true
case SysAttributeTickTopic: case SysAttributeTickTopic, SysAttributeTickTopicNeoFS:
ni.SetTopic(attr.GetValue()) ni.SetTopic(attr.GetValue())
} }
} }

View file

@ -30,11 +30,11 @@ type ObjectServiceClient interface {
// keeping the receiving order. // keeping the receiving order.
// //
// Extended headers can change `Get` behaviour: // Extended headers can change `Get` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// Will try older versions (starting from `__NEOFS__NETMAP_EPOCH` if specified or // Will try older versions (starting from `__NEOFS__NETMAP_EPOCH`/`__FROSTFS__NETMAP_EPOCH` if specified or
// the latest one otherwise) of Network Map to find an object until the depth // the latest one otherwise) of Network Map to find an object until the depth
// limit is reached. // limit is reached.
// //
@ -63,7 +63,7 @@ type ObjectServiceClient interface {
// Chunk messages SHOULD be sent in the direct order of fragmentation. // Chunk messages SHOULD be sent in the direct order of fragmentation.
// //
// Extended headers can change `Put` behaviour: // Extended headers can change `Put` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -94,7 +94,7 @@ type ObjectServiceClient interface {
// guarantee. Object will be marked for removal and deleted eventually. // guarantee. Object will be marked for removal and deleted eventually.
// //
// Extended headers can change `Delete` behaviour: // Extended headers can change `Delete` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -118,7 +118,7 @@ type ObjectServiceClient interface {
// the very minimal information will be returned instead. // the very minimal information will be returned instead.
// //
// Extended headers can change `Head` behaviour: // Extended headers can change `Head` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -144,7 +144,7 @@ type ObjectServiceClient interface {
// Specification section for more details. // Specification section for more details.
// //
// Extended headers can change `Search` behaviour: // Extended headers can change `Search` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -167,10 +167,10 @@ type ObjectServiceClient interface {
// order. // order.
// //
// Extended headers can change `GetRange` behaviour: // Extended headers can change `GetRange` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// Will try older versions of Network Map to find an object until the depth // Will try older versions of Network Map to find an object until the depth
// limit is reached. // limit is reached.
// //
@ -199,10 +199,10 @@ type ObjectServiceClient interface {
// the request. Note that hash is calculated for XORed data. // the request. Note that hash is calculated for XORed data.
// //
// Extended headers can change `GetRangeHash` behaviour: // Extended headers can change `GetRangeHash` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// Will try older versions of Network Map to find an object until the depth // Will try older versions of Network Map to find an object until the depth
// limit is reached. // limit is reached.
// //
@ -402,11 +402,11 @@ type ObjectServiceServer interface {
// keeping the receiving order. // keeping the receiving order.
// //
// Extended headers can change `Get` behaviour: // Extended headers can change `Get` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// Will try older versions (starting from `__NEOFS__NETMAP_EPOCH` if specified or // Will try older versions (starting from `__NEOFS__NETMAP_EPOCH`/`__FROSTFS__NETMAP_EPOCH` if specified or
// the latest one otherwise) of Network Map to find an object until the depth // the latest one otherwise) of Network Map to find an object until the depth
// limit is reached. // limit is reached.
// //
@ -435,7 +435,7 @@ type ObjectServiceServer interface {
// Chunk messages SHOULD be sent in the direct order of fragmentation. // Chunk messages SHOULD be sent in the direct order of fragmentation.
// //
// Extended headers can change `Put` behaviour: // Extended headers can change `Put` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -466,7 +466,7 @@ type ObjectServiceServer interface {
// guarantee. Object will be marked for removal and deleted eventually. // guarantee. Object will be marked for removal and deleted eventually.
// //
// Extended headers can change `Delete` behaviour: // Extended headers can change `Delete` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -490,7 +490,7 @@ type ObjectServiceServer interface {
// the very minimal information will be returned instead. // the very minimal information will be returned instead.
// //
// Extended headers can change `Head` behaviour: // Extended headers can change `Head` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -516,7 +516,7 @@ type ObjectServiceServer interface {
// Specification section for more details. // Specification section for more details.
// //
// Extended headers can change `Search` behaviour: // Extended headers can change `Search` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// //
@ -539,10 +539,10 @@ type ObjectServiceServer interface {
// order. // order.
// //
// Extended headers can change `GetRange` behaviour: // Extended headers can change `GetRange` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// Will try older versions of Network Map to find an object until the depth // Will try older versions of Network Map to find an object until the depth
// limit is reached. // limit is reached.
// //
@ -571,10 +571,10 @@ type ObjectServiceServer interface {
// the request. Note that hash is calculated for XORed data. // the request. Note that hash is calculated for XORed data.
// //
// Extended headers can change `GetRangeHash` behaviour: // Extended headers can change `GetRangeHash` behaviour:
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Will use the requsted version of Network Map for object placement // Will use the requsted version of Network Map for object placement
// calculation. // calculation.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// Will try older versions of Network Map to find an object until the depth // Will try older versions of Network Map to find an object until the depth
// limit is reached. // limit is reached.
// //

View file

@ -556,19 +556,19 @@ func (x *SplitInfo) GetLink() *grpc.ObjectID {
// Objects with duplicated attribute names or attributes with empty values // Objects with duplicated attribute names or attributes with empty values
// will be considered invalid. // will be considered invalid.
// //
// There are some "well-known" attributes starting with `__NEOFS__` prefix // There are some "well-known" attributes starting with `__NEOFS__`/`__FROSTFS__` prefix
// that affect system behaviour: // that affect system behaviour:
// //
// - __NEOFS__UPLOAD_ID \ // - [ __NEOFS__UPLOAD_ID | __FROSTFS__UPLOAD_ID ] \
// Marks smaller parts of a split bigger object // Marks smaller parts of a split bigger object
// - __NEOFS__EXPIRATION_EPOCH \ // - [ __NEOFS__EXPIRATION_EPOCH | __FROSTFS__EXPIRATION_EPOCH ] \
// Tells GC to delete object after that epoch // Tells GC to delete object after that epoch
// - __NEOFS__TICK_EPOCH \ // - [ __NEOFS__TICK_EPOCH | __FROSTFS__TICK_EPOCH ] \
// Decimal number that defines what epoch must produce // Decimal number that defines what epoch must produce
// object notification with UTF-8 object address in a // object notification with UTF-8 object address in a
// body (`0` value produces notification right after // body (`0` value produces notification right after
// object put) // object put)
// - __NEOFS__TICK_TOPIC \ // - [ __NEOFS__TICK_TOPIC | __FROSTFS__TICK_TOPIC ] \
// UTF-8 string topic ID that is used for object notification // UTF-8 string topic ID that is used for object notification
// //
// And some well-known attributes used by applications only: // And some well-known attributes used by applications only:

View file

@ -349,14 +349,14 @@ func (x *SessionToken) GetSignature() *grpc.Signature {
// Responses with duplicated header names or headers with empty values will be // Responses with duplicated header names or headers with empty values will be
// considered invalid. // considered invalid.
// //
// There are some "well-known" headers starting with `__NEOFS__` prefix that // There are some "well-known" headers starting with `__NEOFS__` or `__FROSTFS__` prefix that
// affect system behaviour: // affect system behaviour:
// //
// - __NEOFS__NETMAP_EPOCH \ // - [ __NEOFS__NETMAP_EPOCH | __FROSTFS__NETMAP_EPOCH ] \
// Netmap epoch to use for object placement calculation. The `value` is string // Netmap epoch to use for object placement calculation. The `value` is string
// encoded `uint64` in decimal presentation. If set to '0' or not set, the // encoded `uint64` in decimal presentation. If set to '0' or not set, the
// current epoch only will be used. // current epoch only will be used.
// - __NEOFS__NETMAP_LOOKUP_DEPTH \ // - [ __NEOFS__NETMAP_LOOKUP_DEPTH | __FROSTFS__NETMAP_LOOKUP_DEPTH ] \
// If object can't be found using current epoch's netmap, this header limits // If object can't be found using current epoch's netmap, this header limits
// how many past epochs the node can look up through. The `value` is string // how many past epochs the node can look up through. The `value` is string
// encoded `uint64` in decimal presentation. If set to '0' or not set, only the // encoded `uint64` in decimal presentation. If set to '0' or not set, only the

View file

@ -1,7 +1,7 @@
package session package session
// ReservedXHeaderPrefix is a prefix of keys to "well-known" X-headers. // ReservedXHeaderPrefix is a prefix of keys to "well-known" X-headers.
const ReservedXHeaderPrefix = "__NEOFS__" const ReservedXHeaderPrefix = "__FROSTFS__"
const ( const (
// XHeaderNetmapEpoch is a key to the reserved X-header that specifies netmap epoch // XHeaderNetmapEpoch is a key to the reserved X-header that specifies netmap epoch
@ -14,3 +14,18 @@ const (
// set, the current epoch only will be used. // set, the current epoch only will be used.
XHeaderNetmapLookupDepth = ReservedXHeaderPrefix + "NETMAP_LOOKUP_DEPTH" XHeaderNetmapLookupDepth = ReservedXHeaderPrefix + "NETMAP_LOOKUP_DEPTH"
) )
// ReservedXHeaderPrefixNeoFS is a prefix of keys to "well-known" X-headers.
const ReservedXHeaderPrefixNeoFS = "__NEOFS__"
const (
// XHeaderNetmapEpochNeoFS is a key to the reserved X-header that specifies netmap epoch
// to use for object placement calculation. If set to '0' or not set, the current
// epoch only will be used.
XHeaderNetmapEpochNeoFS = ReservedXHeaderPrefixNeoFS + "NETMAP_EPOCH"
// XHeaderNetmapLookupDepthNeoFS is a key to the reserved X-header that limits
// how many past epochs back the node will can lookup. If set to '0' or not
// set, the current epoch only will be used.
XHeaderNetmapLookupDepthNeoFS = ReservedXHeaderPrefixNeoFS + "NETMAP_LOOKUP_DEPTH"
)

115
signature/body.go Normal file
View file

@ -0,0 +1,115 @@
package signature
import (
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
)
func serviceMessageBody(req interface{}) stableMarshaler {
switch v := req.(type) {
default:
panic(fmt.Sprintf("unsupported session message %T", req))
/* Accounting */
case *accounting.BalanceRequest:
return v.GetBody()
case *accounting.BalanceResponse:
return v.GetBody()
/* Session */
case *session.CreateRequest:
return v.GetBody()
case *session.CreateResponse:
return v.GetBody()
/* Container */
case *container.PutRequest:
return v.GetBody()
case *container.PutResponse:
return v.GetBody()
case *container.DeleteRequest:
return v.GetBody()
case *container.DeleteResponse:
return v.GetBody()
case *container.GetRequest:
return v.GetBody()
case *container.GetResponse:
return v.GetBody()
case *container.ListRequest:
return v.GetBody()
case *container.ListResponse:
return v.GetBody()
case *container.SetExtendedACLRequest:
return v.GetBody()
case *container.SetExtendedACLResponse:
return v.GetBody()
case *container.GetExtendedACLRequest:
return v.GetBody()
case *container.GetExtendedACLResponse:
return v.GetBody()
case *container.AnnounceUsedSpaceRequest:
return v.GetBody()
case *container.AnnounceUsedSpaceResponse:
return v.GetBody()
/* Object */
case *object.PutRequest:
return v.GetBody()
case *object.PutResponse:
return v.GetBody()
case *object.GetRequest:
return v.GetBody()
case *object.GetResponse:
return v.GetBody()
case *object.HeadRequest:
return v.GetBody()
case *object.HeadResponse:
return v.GetBody()
case *object.SearchRequest:
return v.GetBody()
case *object.SearchResponse:
return v.GetBody()
case *object.DeleteRequest:
return v.GetBody()
case *object.DeleteResponse:
return v.GetBody()
case *object.GetRangeRequest:
return v.GetBody()
case *object.GetRangeResponse:
return v.GetBody()
case *object.GetRangeHashRequest:
return v.GetBody()
case *object.GetRangeHashResponse:
return v.GetBody()
/* Netmap */
case *netmap.LocalNodeInfoRequest:
return v.GetBody()
case *netmap.LocalNodeInfoResponse:
return v.GetBody()
case *netmap.NetworkInfoRequest:
return v.GetBody()
case *netmap.NetworkInfoResponse:
return v.GetBody()
case *netmap.SnapshotRequest:
return v.GetBody()
case *netmap.SnapshotResponse:
return v.GetBody()
/* Reputation */
case *reputation.AnnounceLocalTrustRequest:
return v.GetBody()
case *reputation.AnnounceLocalTrustResponse:
return v.GetBody()
case *reputation.AnnounceIntermediateResultRequest:
return v.GetBody()
case *reputation.AnnounceIntermediateResultResponse:
return v.GetBody()
}
}

26
signature/marshaller.go Normal file
View file

@ -0,0 +1,26 @@
package signature
type stableMarshaler interface {
StableMarshal([]byte) []byte
StableSize() int
}
type StableMarshalerWrapper struct {
SM stableMarshaler
}
func (s StableMarshalerWrapper) ReadSignedData(buf []byte) ([]byte, error) {
if s.SM != nil {
return s.SM.StableMarshal(buf), nil
}
return nil, nil
}
func (s StableMarshalerWrapper) SignedDataSize() int {
if s.SM != nil {
return s.SM.StableSize()
}
return 0
}

View file

@ -2,17 +2,12 @@ package signature
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"fmt" "fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/signature" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/signature"
"golang.org/x/sync/errgroup"
) )
type serviceRequest interface { type serviceRequest interface {
@ -27,179 +22,92 @@ type serviceResponse interface {
SetVerificationHeader(*session.ResponseVerificationHeader) SetVerificationHeader(*session.ResponseVerificationHeader)
} }
type stableMarshaler interface { type signatureReceiver interface {
StableMarshal([]byte) []byte
StableSize() int
}
type StableMarshalerWrapper struct {
SM stableMarshaler
}
type metaHeader interface {
stableMarshaler
getOrigin() metaHeader
}
type verificationHeader interface {
stableMarshaler
GetBodySignature() *refs.Signature
SetBodySignature(*refs.Signature) SetBodySignature(*refs.Signature)
GetMetaSignature() *refs.Signature
SetMetaSignature(*refs.Signature) SetMetaSignature(*refs.Signature)
GetOriginSignature() *refs.Signature
SetOriginSignature(*refs.Signature) SetOriginSignature(*refs.Signature)
setOrigin(stableMarshaler)
getOrigin() verificationHeader
}
type requestMetaHeader struct {
*session.RequestMetaHeader
}
type responseMetaHeader struct {
*session.ResponseMetaHeader
}
type requestVerificationHeader struct {
*session.RequestVerificationHeader
}
type responseVerificationHeader struct {
*session.ResponseVerificationHeader
}
func (h *requestMetaHeader) getOrigin() metaHeader {
return &requestMetaHeader{
RequestMetaHeader: h.GetOrigin(),
}
}
func (h *responseMetaHeader) getOrigin() metaHeader {
return &responseMetaHeader{
ResponseMetaHeader: h.GetOrigin(),
}
}
func (h *requestVerificationHeader) getOrigin() verificationHeader {
if origin := h.GetOrigin(); origin != nil {
return &requestVerificationHeader{
RequestVerificationHeader: origin,
}
}
return nil
}
func (h *requestVerificationHeader) setOrigin(m stableMarshaler) {
if m != nil {
h.SetOrigin(m.(*session.RequestVerificationHeader))
}
}
func (r *responseVerificationHeader) getOrigin() verificationHeader {
if origin := r.GetOrigin(); origin != nil {
return &responseVerificationHeader{
ResponseVerificationHeader: origin,
}
}
return nil
}
func (r *responseVerificationHeader) setOrigin(m stableMarshaler) {
if m != nil {
r.SetOrigin(m.(*session.ResponseVerificationHeader))
}
}
func (s StableMarshalerWrapper) ReadSignedData(buf []byte) ([]byte, error) {
if s.SM != nil {
return s.SM.StableMarshal(buf), nil
}
return nil, nil
}
func (s StableMarshalerWrapper) SignedDataSize() int {
if s.SM != nil {
return s.SM.StableSize()
}
return 0
} }
// SignServiceMessage signes service message with key.
func SignServiceMessage(key *ecdsa.PrivateKey, msg interface{}) error { func SignServiceMessage(key *ecdsa.PrivateKey, msg interface{}) error {
var (
body, meta, verifyOrigin stableMarshaler
verifyHdr verificationHeader
verifyHdrSetter func(verificationHeader)
)
switch v := msg.(type) { switch v := msg.(type) {
case nil: case nil:
return nil return nil
case serviceRequest: case serviceRequest:
body = serviceMessageBody(v) return signServiceRequest(key, v)
meta = v.GetMetaHeader()
verifyHdr = &requestVerificationHeader{new(session.RequestVerificationHeader)}
verifyHdrSetter = func(h verificationHeader) {
v.SetVerificationHeader(h.(*requestVerificationHeader).RequestVerificationHeader)
}
if h := v.GetVerificationHeader(); h != nil {
verifyOrigin = h
}
case serviceResponse: case serviceResponse:
body = serviceMessageBody(v) return signServiceResponse(key, v)
meta = v.GetMetaHeader()
verifyHdr = &responseVerificationHeader{new(session.ResponseVerificationHeader)}
verifyHdrSetter = func(h verificationHeader) {
v.SetVerificationHeader(h.(*responseVerificationHeader).ResponseVerificationHeader)
}
if h := v.GetVerificationHeader(); h != nil {
verifyOrigin = h
}
default: default:
panic(fmt.Sprintf("unsupported session message %T", v)) panic(fmt.Sprintf("unsupported session message %T", v))
} }
}
if verifyOrigin == nil { func signServiceRequest(key *ecdsa.PrivateKey, v serviceRequest) error {
result := &session.RequestVerificationHeader{}
body := serviceMessageBody(v)
meta := v.GetMetaHeader()
header := v.GetVerificationHeader()
if err := signMessageParts(key, body, meta, header, header != nil, result); err != nil {
return err
}
result.SetOrigin(header)
v.SetVerificationHeader(result)
return nil
}
func signServiceResponse(key *ecdsa.PrivateKey, v serviceResponse) error {
result := &session.ResponseVerificationHeader{}
body := serviceMessageBody(v)
meta := v.GetMetaHeader()
header := v.GetVerificationHeader()
if err := signMessageParts(key, body, meta, header, header != nil, result); err != nil {
return err
}
result.SetOrigin(header)
v.SetVerificationHeader(result)
return nil
}
func signMessageParts(key *ecdsa.PrivateKey, body, meta, header stableMarshaler, hasHeader bool, result signatureReceiver) error {
eg := &errgroup.Group{}
if !hasHeader {
// sign session message body // sign session message body
if err := signServiceMessagePart(key, body, verifyHdr.SetBodySignature); err != nil { eg.Go(func() error {
return fmt.Errorf("could not sign body: %w", err) if err := signServiceMessagePart(key, body, result.SetBodySignature); err != nil {
} return fmt.Errorf("could not sign body: %w", err)
}
return nil
})
} }
// sign meta header // sign meta header
if err := signServiceMessagePart(key, meta, verifyHdr.SetMetaSignature); err != nil { eg.Go(func() error {
return fmt.Errorf("could not sign meta header: %w", err) if err := signServiceMessagePart(key, meta, result.SetMetaSignature); err != nil {
} return fmt.Errorf("could not sign meta header: %w", err)
}
return nil
})
// sign verification header origin // sign verification header origin
if err := signServiceMessagePart(key, verifyOrigin, verifyHdr.SetOriginSignature); err != nil { eg.Go(func() error {
return fmt.Errorf("could not sign origin of verification header: %w", err) if err := signServiceMessagePart(key, header, result.SetOriginSignature); err != nil {
} return fmt.Errorf("could not sign origin of verification header: %w", err)
}
// wrap origin verification header return nil
verifyHdr.setOrigin(verifyOrigin) })
return eg.Wait()
// update matryoshka verification header
verifyHdrSetter(verifyHdr)
return nil
} }
func signServiceMessagePart(key *ecdsa.PrivateKey, part stableMarshaler, sigWrite func(*refs.Signature)) error { func signServiceMessagePart(key *ecdsa.PrivateKey, part stableMarshaler, sigWrite func(*refs.Signature)) error {
var sig *refs.Signature var sig *refs.Signature
wrapper := StableMarshalerWrapper{
SM: part,
}
// sign part // sign part
if err := signature.SignDataWithHandler( if err := signature.SignDataWithHandler(
key, key,
&StableMarshalerWrapper{part}, wrapper,
func(s *refs.Signature) { func(s *refs.Signature) {
sig = s sig = s
}, },
@ -212,182 +120,3 @@ func signServiceMessagePart(key *ecdsa.PrivateKey, part stableMarshaler, sigWrit
return nil return nil
} }
func VerifyServiceMessage(msg interface{}) error {
var (
meta metaHeader
verify verificationHeader
)
switch v := msg.(type) {
case nil:
return nil
case serviceRequest:
meta = &requestMetaHeader{
RequestMetaHeader: v.GetMetaHeader(),
}
verify = &requestVerificationHeader{
RequestVerificationHeader: v.GetVerificationHeader(),
}
case serviceResponse:
meta = &responseMetaHeader{
ResponseMetaHeader: v.GetMetaHeader(),
}
verify = &responseVerificationHeader{
ResponseVerificationHeader: v.GetVerificationHeader(),
}
default:
panic(fmt.Sprintf("unsupported session message %T", v))
}
body := serviceMessageBody(msg)
size := body.StableSize()
if sz := meta.StableSize(); sz > size {
size = sz
}
if sz := verify.StableSize(); sz > size {
size = sz
}
buf := make([]byte, 0, size)
return verifyMatryoshkaLevel(body, meta, verify, buf)
}
func verifyMatryoshkaLevel(body stableMarshaler, meta metaHeader, verify verificationHeader, buf []byte) error {
if err := verifyServiceMessagePart(meta, verify.GetMetaSignature, buf); err != nil {
return fmt.Errorf("could not verify meta header: %w", err)
}
origin := verify.getOrigin()
if err := verifyServiceMessagePart(origin, verify.GetOriginSignature, buf); err != nil {
return fmt.Errorf("could not verify origin of verification header: %w", err)
}
if origin == nil {
if err := verifyServiceMessagePart(body, verify.GetBodySignature, buf); err != nil {
return fmt.Errorf("could not verify body: %w", err)
}
return nil
}
if verify.GetBodySignature() != nil {
return errors.New("body signature at the matryoshka upper level")
}
return verifyMatryoshkaLevel(body, meta.getOrigin(), origin, buf)
}
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature, buf []byte) error {
return signature.VerifyDataWithSource(
&StableMarshalerWrapper{part},
sigRdr,
signature.WithBuffer(buf),
)
}
func serviceMessageBody(req interface{}) stableMarshaler {
switch v := req.(type) {
default:
panic(fmt.Sprintf("unsupported session message %T", req))
/* Accounting */
case *accounting.BalanceRequest:
return v.GetBody()
case *accounting.BalanceResponse:
return v.GetBody()
/* Session */
case *session.CreateRequest:
return v.GetBody()
case *session.CreateResponse:
return v.GetBody()
/* Container */
case *container.PutRequest:
return v.GetBody()
case *container.PutResponse:
return v.GetBody()
case *container.DeleteRequest:
return v.GetBody()
case *container.DeleteResponse:
return v.GetBody()
case *container.GetRequest:
return v.GetBody()
case *container.GetResponse:
return v.GetBody()
case *container.ListRequest:
return v.GetBody()
case *container.ListResponse:
return v.GetBody()
case *container.SetExtendedACLRequest:
return v.GetBody()
case *container.SetExtendedACLResponse:
return v.GetBody()
case *container.GetExtendedACLRequest:
return v.GetBody()
case *container.GetExtendedACLResponse:
return v.GetBody()
case *container.AnnounceUsedSpaceRequest:
return v.GetBody()
case *container.AnnounceUsedSpaceResponse:
return v.GetBody()
/* Object */
case *object.PutRequest:
return v.GetBody()
case *object.PutResponse:
return v.GetBody()
case *object.GetRequest:
return v.GetBody()
case *object.GetResponse:
return v.GetBody()
case *object.HeadRequest:
return v.GetBody()
case *object.HeadResponse:
return v.GetBody()
case *object.SearchRequest:
return v.GetBody()
case *object.SearchResponse:
return v.GetBody()
case *object.DeleteRequest:
return v.GetBody()
case *object.DeleteResponse:
return v.GetBody()
case *object.GetRangeRequest:
return v.GetBody()
case *object.GetRangeResponse:
return v.GetBody()
case *object.GetRangeHashRequest:
return v.GetBody()
case *object.GetRangeHashResponse:
return v.GetBody()
/* Netmap */
case *netmap.LocalNodeInfoRequest:
return v.GetBody()
case *netmap.LocalNodeInfoResponse:
return v.GetBody()
case *netmap.NetworkInfoRequest:
return v.GetBody()
case *netmap.NetworkInfoResponse:
return v.GetBody()
case *netmap.SnapshotRequest:
return v.GetBody()
case *netmap.SnapshotResponse:
return v.GetBody()
/* Reputation */
case *reputation.AnnounceLocalTrustRequest:
return v.GetBody()
case *reputation.AnnounceLocalTrustResponse:
return v.GetBody()
case *reputation.AnnounceIntermediateResultRequest:
return v.GetBody()
case *reputation.AnnounceIntermediateResultResponse:
return v.GetBody()
}
}

View file

@ -70,3 +70,56 @@ func TestBalanceResponse(t *testing.T) {
// verification must fail // verification must fail
require.Error(t, VerifyServiceMessage(req)) require.Error(t, VerifyServiceMessage(req))
} }
func BenchmarkSignRequest(b *testing.B) {
key, _ := crypto.LoadPrivateKey("Kwk6k2eC3L3QuPvD8aiaNyoSXgQ2YL1bwS5CP1oKoA9waeAze97s")
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
b.StopTimer()
dec := new(accounting.Decimal)
dec.SetValue(100)
body := new(accounting.BalanceResponseBody)
body.SetBalance(dec)
meta := new(session.ResponseMetaHeader)
meta.SetTTL(1)
resp := new(accounting.BalanceResponse)
resp.SetBody(body)
resp.SetMetaHeader(meta)
b.StartTimer()
SignServiceMessage(key, resp)
}
}
func BenchmarkVerifyRequest(b *testing.B) {
key, _ := crypto.LoadPrivateKey("Kwk6k2eC3L3QuPvD8aiaNyoSXgQ2YL1bwS5CP1oKoA9waeAze97s")
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
b.StopTimer()
dec := new(accounting.Decimal)
dec.SetValue(100)
body := new(accounting.BalanceResponseBody)
body.SetBalance(dec)
meta := new(session.ResponseMetaHeader)
meta.SetTTL(1)
resp := new(accounting.BalanceResponse)
resp.SetBody(body)
resp.SetMetaHeader(meta)
SignServiceMessage(key, resp)
b.StartTimer()
VerifyServiceMessage(resp)
}
}

127
signature/verify.go Normal file
View file

@ -0,0 +1,127 @@
package signature
import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/signature"
"golang.org/x/sync/errgroup"
)
type signatureProvider interface {
GetBodySignature() *refs.Signature
GetMetaSignature() *refs.Signature
GetOriginSignature() *refs.Signature
}
// VerifyServiceMessage verifies service message.
func VerifyServiceMessage(msg interface{}) error {
switch v := msg.(type) {
case nil:
return nil
case serviceRequest:
return verifyServiceRequest(v)
case serviceResponse:
return verifyServiceResponse(v)
default:
panic(fmt.Sprintf("unsupported session message %T", v))
}
}
func verifyServiceRequest(v serviceRequest) error {
meta := v.GetMetaHeader()
verificationHeader := v.GetVerificationHeader()
body := serviceMessageBody(v)
return verifyServiceRequestRecursive(body, meta, verificationHeader)
}
func verifyServiceRequestRecursive(body stableMarshaler, meta *session.RequestMetaHeader, verify *session.RequestVerificationHeader) error {
verificationHeaderOrigin := verify.GetOrigin()
metaOrigin := meta.GetOrigin()
stop, err := verifyMessageParts(body, meta, verificationHeaderOrigin, verificationHeaderOrigin != nil, verify)
if err != nil {
return err
}
if stop {
return nil
}
return verifyServiceRequestRecursive(body, metaOrigin, verificationHeaderOrigin)
}
func verifyMessageParts(body, meta, originHeader stableMarshaler, hasOriginHeader bool, sigProvider signatureProvider) (stop bool, err error) {
eg := &errgroup.Group{}
eg.Go(func() error {
if err := verifyServiceMessagePart(meta, sigProvider.GetMetaSignature); err != nil {
return fmt.Errorf("could not verify meta header: %w", err)
}
return nil
})
eg.Go(func() error {
if err := verifyServiceMessagePart(originHeader, sigProvider.GetOriginSignature); err != nil {
return fmt.Errorf("could not verify origin of verification header: %w", err)
}
return nil
})
if !hasOriginHeader {
eg.Go(func() error {
if err := verifyServiceMessagePart(body, sigProvider.GetBodySignature); err != nil {
return fmt.Errorf("could not verify body: %w", err)
}
return nil
})
}
if err := eg.Wait(); err != nil {
return false, err
}
if !hasOriginHeader {
return true, nil
}
if sigProvider.GetBodySignature() != nil {
return false, errors.New("body signature misses at the matryoshka upper level")
}
return false, nil
}
func verifyServiceResponse(v serviceResponse) error {
meta := v.GetMetaHeader()
verificationHeader := v.GetVerificationHeader()
body := serviceMessageBody(v)
return verifyServiceResponseRecursive(body, meta, verificationHeader)
}
func verifyServiceResponseRecursive(body stableMarshaler, meta *session.ResponseMetaHeader, verify *session.ResponseVerificationHeader) error {
verificationHeaderOrigin := verify.GetOrigin()
metaOrigin := meta.GetOrigin()
stop, err := verifyMessageParts(body, meta, verificationHeaderOrigin, verificationHeaderOrigin != nil, verify)
if err != nil {
return err
}
if stop {
return nil
}
return verifyServiceResponseRecursive(body, metaOrigin, verificationHeaderOrigin)
}
func verifyServiceMessagePart(part stableMarshaler, sigRdr func() *refs.Signature) error {
wrapper := StableMarshalerWrapper{
SM: part,
}
return signature.VerifyDataWithSource(
wrapper,
sigRdr,
)
}

View file

@ -27,7 +27,7 @@ const (
// contains objects from the same container. // contains objects from the same container.
// //
// Being an object payload, StorageGroup may have expiration Epoch set with // Being an object payload, StorageGroup may have expiration Epoch set with
// `__NEOFS__EXPIRATION_EPOCH` well-known attribute. When expired, StorageGroup // `__NEOFS__EXPIRATION_EPOCH`/`__FROSTFS__EXPIRATION_EPOCH` well-known attribute. When expired, StorageGroup
// will be ignored by InnerRing nodes during Data Audit cycles and will be // will be ignored by InnerRing nodes during Data Audit cycles and will be
// deleted by Storage Nodes. // deleted by Storage Nodes.
type StorageGroup struct { type StorageGroup struct {

View file

@ -30,7 +30,7 @@ type Tombstone struct {
// Last NeoFS epoch number of the tombstone lifetime. It's set by the tombstone // Last NeoFS epoch number of the tombstone lifetime. It's set by the tombstone
// creator depending on the current NeoFS network settings. A tombstone object // creator depending on the current NeoFS network settings. A tombstone object
// must have the same expiration epoch value in `__NEOFS__EXPIRATION_EPOCH` // must have the same expiration epoch value in `__NEOFS__EXPIRATION_EPOCH`/`__FROSTFS__EXPIRATION_EPOCH`
// attribute. Otherwise, the tombstone will be rejected by a storage node. // attribute. Otherwise, the tombstone will be rejected by a storage node.
ExpirationEpoch uint64 `protobuf:"varint,1,opt,name=expiration_epoch,json=expirationEpoch,proto3" json:"expiration_epoch,omitempty"` ExpirationEpoch uint64 `protobuf:"varint,1,opt,name=expiration_epoch,json=expirationEpoch,proto3" json:"expiration_epoch,omitempty"`
// 16 byte UUID used to identify the split object hierarchy parts. Must be // 16 byte UUID used to identify the split object hierarchy parts. Must be

29
util/signature/buffer.go Normal file
View file

@ -0,0 +1,29 @@
package signature
import "sync"
const poolSliceMaxSize = 64 * 1024
var buffersPool = sync.Pool{
New: func() any {
return make([]byte, 0)
},
}
func newBufferFromPool(size int) []byte {
result := buffersPool.Get().([]byte)
if cap(result) < size {
result = make([]byte, size)
} else {
result = result[:size]
}
return result
}
func returnBufferToPool(buf []byte) {
if cap(buf) > poolSliceMaxSize {
return
}
buf = buf[:0]
buffersPool.Put(buf)
}

View file

@ -35,7 +35,10 @@ func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySigna
opts[i](cfg) opts[i](cfg)
} }
data, err := readSignedData(cfg, src) buffer := newBufferFromPool(src.SignedDataSize())
defer returnBufferToPool(buffer)
data, err := src.ReadSignedData(buffer)
if err != nil { if err != nil {
return err return err
} }
@ -61,7 +64,10 @@ func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts ..
opts[i](cfg) opts[i](cfg)
} }
data, err := readSignedData(cfg, dataSrc) buffer := newBufferFromPool(dataSrc.SignedDataSize())
defer returnBufferToPool(buffer)
data, err := dataSrc.ReadSignedData(buffer)
if err != nil { if err != nil {
return err return err
} }
@ -76,13 +82,3 @@ func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) er
func VerifyData(src DataWithSignature, opts ...SignOption) error { func VerifyData(src DataWithSignature, opts ...SignOption) error {
return VerifyDataWithSource(src, src.GetSignature, opts...) return VerifyDataWithSource(src, src.GetSignature, opts...)
} }
func readSignedData(cfg *cfg, src DataSource) ([]byte, error) {
size := src.SignedDataSize()
if cfg.buffer == nil || cap(cfg.buffer) < size {
cfg.buffer = make([]byte, size)
} else {
cfg.buffer = cfg.buffer[:size]
}
return src.ReadSignedData(cfg.buffer)
}

View file

@ -13,7 +13,6 @@ import (
type cfg struct { type cfg struct {
schemeFixed bool schemeFixed bool
scheme refs.SignatureScheme scheme refs.SignatureScheme
buffer []byte
} }
func defaultCfg() *cfg { func defaultCfg() *cfg {
@ -36,9 +35,10 @@ func verify(cfg *cfg, data []byte, sig *refs.Signature) error {
case refs.ECDSA_RFC6979_SHA256: case refs.ECDSA_RFC6979_SHA256:
return crypto.VerifyRFC6979(pub, data, sig.GetSign()) return crypto.VerifyRFC6979(pub, data, sig.GetSign())
case refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT: case refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT:
buf := make([]byte, base64.StdEncoding.EncodedLen(len(data))) buffer := newBufferFromPool(base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(buf, data) defer returnBufferToPool(buffer)
if !walletconnect.Verify(pub, buf, sig.GetSign()) { base64.StdEncoding.Encode(buffer, data)
if !walletconnect.Verify(pub, buffer, sig.GetSign()) {
return crypto.ErrInvalidSignature return crypto.ErrInvalidSignature
} }
return nil return nil
@ -54,9 +54,10 @@ func sign(cfg *cfg, key *ecdsa.PrivateKey, data []byte) ([]byte, error) {
case refs.ECDSA_RFC6979_SHA256: case refs.ECDSA_RFC6979_SHA256:
return crypto.SignRFC6979(key, data) return crypto.SignRFC6979(key, data)
case refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT: case refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT:
buf := make([]byte, base64.StdEncoding.EncodedLen(len(data))) buffer := newBufferFromPool(base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(buf, data) defer returnBufferToPool(buffer)
return walletconnect.Sign(key, buf) base64.StdEncoding.Encode(buffer, data)
return walletconnect.Sign(key, buffer)
default: default:
panic(fmt.Sprintf("unsupported scheme %s", cfg.scheme)) panic(fmt.Sprintf("unsupported scheme %s", cfg.scheme))
} }
@ -69,13 +70,6 @@ func SignWithRFC6979() SignOption {
} }
} }
// WithBuffer allows providing pre-allocated buffer for signature verification.
func WithBuffer(buf []byte) SignOption {
return func(c *cfg) {
c.buffer = buf
}
}
func SignWithWalletConnect() SignOption { func SignWithWalletConnect() SignOption {
return func(c *cfg) { return func(c *cfg) {
c.scheme = refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT c.scheme = refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT