From f1a5a0ccd785b50c0728e166c0c995c66bb7917a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 14 Nov 2023 11:16:16 +0000 Subject: [PATCH] returning 'nil' for non-existing origin as opposed to an empty string (#4135) * returning 'nil' for non-existing origin as opposed to an empty string * version bump --- Cargo.lock | 8 ++++---- nym-browser-extension/storage/Cargo.toml | 2 +- nym-wallet/package.json | 2 +- .../codegen/contract-clients/package.json | 2 +- sdk/typescript/docs/package.json | 10 +++++----- .../examples/chat-app/parcel/package.json | 2 +- .../examples/chat-app/plain-html/package.json | 2 +- .../package.json | 2 +- .../examples/chrome-extension/package.json | 2 +- .../examples/firefox-extension/package.json | 2 +- .../examples/mix-fetch/browser/package.json | 2 +- .../examples/node-tester/parcel/package.json | 2 +- .../node-tester/plain-html/package.json | 2 +- .../examples/node-tester/react/package.json | 2 +- .../packages/mix-fetch-node/package.json | 6 +++--- .../mix-fetch/internal-dev/package.json | 2 +- .../internal-dev/parcel/package.json | 2 +- .../packages/mix-fetch/package.json | 6 +++--- .../packages/node-tester/package.json | 6 +++--- .../packages/nodejs-client/package.json | 6 +++--- .../packages/sdk-react/package.json | 2 +- sdk/typescript/packages/sdk/package.json | 6 +++--- wasm/client/Cargo.toml | 2 +- wasm/mix-fetch/Cargo.toml | 2 +- .../internal/jstypes/conv/request.go | 4 ++-- .../go-mix-conn/internal/jstypes/globals.go | 20 ++++++++++++------- .../go-mix-conn/internal/mixfetch/mixfetch.go | 15 +++++++++++--- wasm/node-tester/Cargo.toml | 2 +- 28 files changed, 69 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4505e78707..34fcff383f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2994,7 +2994,7 @@ dependencies = [ [[package]] name = "extension-storage" -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" dependencies = [ "bip39", "console_error_panic_hook", @@ -5568,7 +5568,7 @@ dependencies = [ [[package]] name = "mix-fetch-wasm" -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" dependencies = [ "async-trait", "futures", @@ -6270,7 +6270,7 @@ dependencies = [ [[package]] name = "nym-client-wasm" -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" dependencies = [ "anyhow", "futures", @@ -6972,7 +6972,7 @@ dependencies = [ [[package]] name = "nym-node-tester-wasm" -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" dependencies = [ "futures", "js-sys", diff --git a/nym-browser-extension/storage/Cargo.toml b/nym-browser-extension/storage/Cargo.toml index 02661e3284..037386774c 100644 --- a/nym-browser-extension/storage/Cargo.toml +++ b/nym-browser-extension/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "extension-storage" -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" edition = "2021" license = "Apache-2.0" repository = "https://github.com/nymtech/nym" diff --git a/nym-wallet/package.json b/nym-wallet/package.json index 5a011cdee1..f0d1b31155 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/nym-wallet-app", - "version": "1.2.12-rc.1", + "version": "1.2.12-rc.2", "license": "MIT", "main": "index.js", "scripts": { diff --git a/sdk/typescript/codegen/contract-clients/package.json b/sdk/typescript/codegen/contract-clients/package.json index 99f6bf253a..b4f91a948b 100644 --- a/sdk/typescript/codegen/contract-clients/package.json +++ b/sdk/typescript/codegen/contract-clients/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/contract-clients", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "description": "A client for all Nym smart contracts", "license": "Apache-2.0", "author": "Nym Technologies SA", diff --git a/sdk/typescript/docs/package.json b/sdk/typescript/docs/package.json index 2d877b8888..f4c99e0a38 100644 --- a/sdk/typescript/docs/package.json +++ b/sdk/typescript/docs/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/ts-sdk-docs", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "description": "Nym Typescript SDK Docs", "license": "Apache-2.0", "author": "Nym Technologies SA", @@ -28,9 +28,9 @@ "@mui/icons-material": "^5.14.9", "@mui/lab": "^5.0.0-alpha.145", "@mui/material": "^5.14.8", - "@nymproject/contract-clients": ">=1.2.4-rc.1 || ^1", - "@nymproject/mix-fetch-full-fat": ">=1.2.4-rc.1 || ^1", - "@nymproject/sdk-full-fat": ">=1.2.4-rc.1 || ^1", + "@nymproject/contract-clients": ">=1.2.4-rc.2 || ^1", + "@nymproject/mix-fetch-full-fat": ">=1.2.4-rc.2 || ^1", + "@nymproject/sdk-full-fat": ">=1.2.4-rc.2 || ^1", "chain-registry": "^1.19.0", "cosmjs-types": "^0.8.0", "next": "^13.4.19", @@ -50,4 +50,4 @@ "typescript": "^4.9.3" }, "private": false -} \ No newline at end of file +} diff --git a/sdk/typescript/examples/chat-app/parcel/package.json b/sdk/typescript/examples/chat-app/parcel/package.json index 5902778256..0f9dbebffd 100644 --- a/sdk/typescript/examples/chat-app/parcel/package.json +++ b/sdk/typescript/examples/chat-app/parcel/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-plain-html-parcel", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "An example project that uses WASM and plain HTML bundled with Parcel v2", "license": "Apache-2.0", "scripts": { diff --git a/sdk/typescript/examples/chat-app/plain-html/package.json b/sdk/typescript/examples/chat-app/plain-html/package.json index 907de17a93..4d3915855c 100644 --- a/sdk/typescript/examples/chat-app/plain-html/package.json +++ b/sdk/typescript/examples/chat-app/plain-html/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-plain-html", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "An example project that uses WASM and plain HTML", "license": "Apache-2.0", "scripts": { diff --git a/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/package.json b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/package.json index 076ad4ebf3..6deb168308 100644 --- a/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/package.json +++ b/sdk/typescript/examples/chat-app/react-webpack-with-theme-example/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-react-webpack-wasm", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "An example project that uses WASM, React, Webpack, Typescript and the Nym theme + components library", "license": "Apache-2.0", "scripts": { diff --git a/sdk/typescript/examples/chrome-extension/package.json b/sdk/typescript/examples/chrome-extension/package.json index 167863bd7c..4a3759680a 100644 --- a/sdk/typescript/examples/chrome-extension/package.json +++ b/sdk/typescript/examples/chrome-extension/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-chrome-extension", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "This is an example of how Nym can be used within the context of a Chrome extension.", "license": "ISC", "author": "", diff --git a/sdk/typescript/examples/firefox-extension/package.json b/sdk/typescript/examples/firefox-extension/package.json index 8204cf7e13..9ca8a5111b 100644 --- a/sdk/typescript/examples/firefox-extension/package.json +++ b/sdk/typescript/examples/firefox-extension/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-firefox-extension", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "This is an example of how Nym can be used within the context of a Firefox extension.", "license": "ISC", "author": "", diff --git a/sdk/typescript/examples/mix-fetch/browser/package.json b/sdk/typescript/examples/mix-fetch/browser/package.json index 69efa51b2f..c5e4ffbdcd 100644 --- a/sdk/typescript/examples/mix-fetch/browser/package.json +++ b/sdk/typescript/examples/mix-fetch/browser/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch-example-parcel", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "license": "Apache-2.0", "scripts": { "build": "parcel build --no-cache --no-content-hash", diff --git a/sdk/typescript/examples/node-tester/parcel/package.json b/sdk/typescript/examples/node-tester/parcel/package.json index 311361410d..12dc69acf7 100644 --- a/sdk/typescript/examples/node-tester/parcel/package.json +++ b/sdk/typescript/examples/node-tester/parcel/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-node-tester-plain-html-parcel", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "An example project that uses WASM and plain HTML bundled with Parcel v2", "license": "Apache-2.0", "scripts": { diff --git a/sdk/typescript/examples/node-tester/plain-html/package.json b/sdk/typescript/examples/node-tester/plain-html/package.json index 8e9c645e1c..4fe5e3b7be 100644 --- a/sdk/typescript/examples/node-tester/plain-html/package.json +++ b/sdk/typescript/examples/node-tester/plain-html/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-node-tester-plain-html", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "An example project that uses WASM node tester and plain HTML", "license": "Apache-2.0", "scripts": { diff --git a/sdk/typescript/examples/node-tester/react/package.json b/sdk/typescript/examples/node-tester/react/package.json index e391f87d5a..db804c92fa 100644 --- a/sdk/typescript/examples/node-tester/react/package.json +++ b/sdk/typescript/examples/node-tester/react/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-example-node-tester-react", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "description": "An example project that uses WASM node tester and React", "license": "Apache-2.0", "scripts": { diff --git a/sdk/typescript/packages/mix-fetch-node/package.json b/sdk/typescript/packages/mix-fetch-node/package.json index 07f345c9c8..3367b87244 100644 --- a/sdk/typescript/packages/mix-fetch-node/package.json +++ b/sdk/typescript/packages/mix-fetch-node/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch-node", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "description": "This package is a drop-in replacement for `fetch` in NodeJS to send HTTP requests over the Nym Mixnet.", "license": "Apache-2.0", "author": "Nym Technologies SA", @@ -28,7 +28,7 @@ "tsc": "tsc --noEmit true" }, "dependencies": { - "@nymproject/mix-fetch-wasm-node": ">=1.2.4-rc.1 || ^1", + "@nymproject/mix-fetch-wasm-node": ">=1.2.4-rc.2 || ^1", "comlink": "^4.3.1", "fake-indexeddb": "^5.0.0", "node-fetch": "^3.3.2", @@ -68,4 +68,4 @@ }, "private": false, "types": "./dist/cjs/index.d.ts" -} \ No newline at end of file +} diff --git a/sdk/typescript/packages/mix-fetch/internal-dev/package.json b/sdk/typescript/packages/mix-fetch/internal-dev/package.json index ffee8a5c7c..8c97273244 100644 --- a/sdk/typescript/packages/mix-fetch/internal-dev/package.json +++ b/sdk/typescript/packages/mix-fetch/internal-dev/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch-tester-webpack", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "license": "Apache-2.0", "scripts": { "build": "webpack build --progress --config webpack.prod.js", diff --git a/sdk/typescript/packages/mix-fetch/internal-dev/parcel/package.json b/sdk/typescript/packages/mix-fetch/internal-dev/parcel/package.json index 4a92c88588..1aa9dc375d 100644 --- a/sdk/typescript/packages/mix-fetch/internal-dev/parcel/package.json +++ b/sdk/typescript/packages/mix-fetch/internal-dev/parcel/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch-tester-parcel", - "version": "1.0.4-rc.1", + "version": "1.0.4-rc.2", "license": "Apache-2.0", "scripts": { "build": "npx parcel build --no-cache --no-content-hash", diff --git a/sdk/typescript/packages/mix-fetch/package.json b/sdk/typescript/packages/mix-fetch/package.json index d0b060a186..381ea96372 100644 --- a/sdk/typescript/packages/mix-fetch/package.json +++ b/sdk/typescript/packages/mix-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "description": "This package is a drop-in replacement for `fetch` to send HTTP requests over the Nym Mixnet.", "license": "Apache-2.0", "author": "Nym Technologies SA", @@ -34,7 +34,7 @@ "tsc": "tsc --noEmit true" }, "dependencies": { - "@nymproject/mix-fetch-wasm": ">=1.2.4-rc.1 || ^1", + "@nymproject/mix-fetch-wasm": ">=1.2.4-rc.2 || ^1", "comlink": "^4.3.1" }, "devDependencies": { @@ -82,4 +82,4 @@ "private": false, "type": "module", "types": "./dist/esm/index.d.ts" -} \ No newline at end of file +} diff --git a/sdk/typescript/packages/node-tester/package.json b/sdk/typescript/packages/node-tester/package.json index bb585756be..eb377423bd 100644 --- a/sdk/typescript/packages/node-tester/package.json +++ b/sdk/typescript/packages/node-tester/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/node-tester", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "description": "This package provides a tester that can send test packets to mixnode that is part of the Nym Mixnet.", "license": "Apache-2.0", "author": "Nym Technologies SA", @@ -25,7 +25,7 @@ "tsc": "tsc --noEmit true" }, "dependencies": { - "@nymproject/nym-node-tester-wasm": ">=1.2.4-rc.1 || ^1", + "@nymproject/nym-node-tester-wasm": ">=1.2.4-rc.2 || ^1", "comlink": "^4.3.1" }, "devDependencies": { @@ -71,4 +71,4 @@ "private": false, "type": "module", "types": "./dist/esm/index.d.ts" -} \ No newline at end of file +} diff --git a/sdk/typescript/packages/nodejs-client/package.json b/sdk/typescript/packages/nodejs-client/package.json index cc73204f02..e8df393fc4 100644 --- a/sdk/typescript/packages/nodejs-client/package.json +++ b/sdk/typescript/packages/nodejs-client/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/nodejs-client", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "license": "Apache-2.0", "author": "Nym Technologies SA", "files": [ @@ -25,7 +25,7 @@ "tsc": "tsc --noEmit true" }, "dependencies": { - "@nymproject/nym-client-wasm-node": ">=1.2.4-rc.1 || ^1", + "@nymproject/nym-client-wasm-node": ">=1.2.4-rc.2 || ^1", "comlink": "^4.3.1", "fake-indexeddb": "^4.0.2", "rollup-plugin-polyfill": "^4.2.0", @@ -66,4 +66,4 @@ }, "private": false, "types": "./dist/index.d.ts" -} \ No newline at end of file +} diff --git a/sdk/typescript/packages/sdk-react/package.json b/sdk/typescript/packages/sdk-react/package.json index 3d5077c292..6a163d7269 100644 --- a/sdk/typescript/packages/sdk-react/package.json +++ b/sdk/typescript/packages/sdk-react/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-react", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "license": "Apache-2.0", "author": "Nym Technologies SA", "files": [ diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index 5a54835cf4..fabc99574a 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk", - "version": "1.2.4-rc.1", + "version": "1.2.4-rc.2", "license": "Apache-2.0", "author": "Nym Technologies SA", "files": [ @@ -31,7 +31,7 @@ "tsc": "tsc --noEmit true" }, "dependencies": { - "@nymproject/nym-client-wasm": ">=1.2.4-rc.1 || ^1", + "@nymproject/nym-client-wasm": ">=1.2.4-rc.2 || ^1", "comlink": "^4.3.1" }, "devDependencies": { @@ -81,4 +81,4 @@ "private": false, "type": "module", "types": "./dist/esm/index.d.ts" -} \ No newline at end of file +} diff --git a/wasm/client/Cargo.toml b/wasm/client/Cargo.toml index 1dcaa740b1..6961325d61 100644 --- a/wasm/client/Cargo.toml +++ b/wasm/client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nym-client-wasm" authors = ["Dave Hrycyszyn ", "Jedrzej Stuczynski "] -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" edition = "2021" keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"] license = "Apache-2.0" diff --git a/wasm/mix-fetch/Cargo.toml b/wasm/mix-fetch/Cargo.toml index 641650a958..298335d6b5 100644 --- a/wasm/mix-fetch/Cargo.toml +++ b/wasm/mix-fetch/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mix-fetch-wasm" authors = ["Jedrzej Stuczynski "] -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" edition = "2021" keywords = ["nym", "fetch", "wasm", "webassembly", "privacy"] license = "Apache-2.0" diff --git a/wasm/mix-fetch/go-mix-conn/internal/jstypes/conv/request.go b/wasm/mix-fetch/go-mix-conn/internal/jstypes/conv/request.go index 883ce82724..19792dbc06 100644 --- a/wasm/mix-fetch/go-mix-conn/internal/jstypes/conv/request.go +++ b/wasm/mix-fetch/go-mix-conn/internal/jstypes/conv/request.go @@ -195,7 +195,7 @@ func parseHeaders(headers js.Value, reqOpts types.RequestOptions, method string) // 3.1.1 origin := jstypes.Origin() - serializedOrigin := &origin + serializedOrigin := origin // Reference: https://fetch.spec.whatwg.org/#origin-header // TODO: 3.1.2: check response tainting // 3.1.3 @@ -224,7 +224,7 @@ func parseBody(request *js.Value) (io.Reader, error) { jsBody := request.Get(fieldRequestBody) var bodyReader io.Reader - if jsBody.InstanceOf(js.Global().Get("ReadableStream")) && jsBody.Get("getReader").Type() == js.TypeFunction { + if jsBody.InstanceOf(js.Global().Get("ReadableStream")) && jsBody.Get("getReader").Type() == js.TypeFunction { // Check to see if getReader is a function log.Debug("stream body - getReader") bodyReader = external.NewStreamReader(jsBody.Call("getReader")) diff --git a/wasm/mix-fetch/go-mix-conn/internal/jstypes/globals.go b/wasm/mix-fetch/go-mix-conn/internal/jstypes/globals.go index 51dda48c8e..86e7ee3e0e 100644 --- a/wasm/mix-fetch/go-mix-conn/internal/jstypes/globals.go +++ b/wasm/mix-fetch/go-mix-conn/internal/jstypes/globals.go @@ -20,20 +20,26 @@ var ( Headers = js.Global().Get("Headers") ) -func Origin() string { +func Origin() *string { // nodejs doesn't have origin location := js.Global().Get("location") if !location.IsUndefined() && !location.IsNull() { - return location.Get("origin").String() + origin := location.Get("origin").String() + return &origin } else { - return "" + return nil } } func OriginUrl() *url.URL { - originUrl, originErr := url.Parse(Origin()) - if originErr != nil { - panic(fmt.Sprintf("could not obtain origin: %s", originErr)) + origin := Origin() + if origin == nil { + return nil + } else { + originUrl, originErr := url.Parse(*origin) + if originErr != nil { + panic(fmt.Sprintf("could not obtain origin: %s", originErr)) + } + return originUrl } - return originUrl } diff --git a/wasm/mix-fetch/go-mix-conn/internal/mixfetch/mixfetch.go b/wasm/mix-fetch/go-mix-conn/internal/mixfetch/mixfetch.go index 3dbc4c077f..7725be27b6 100644 --- a/wasm/mix-fetch/go-mix-conn/internal/mixfetch/mixfetch.go +++ b/wasm/mix-fetch/go-mix-conn/internal/mixfetch/mixfetch.go @@ -92,7 +92,7 @@ func mainFetchChecks(req *conv.ParsedRequest) error { return nil } if req.Options.Mode == jstypes.ModeSameOrigin { - return errors.New(fmt.Sprintf("MixFetch API cannot load %s. Request mode is \"%s\" but the URL's origin is not same as the request origin %s.", req.Request.URL.String(), jstypes.ModeSameOrigin, jstypes.Origin)) + return errors.New(fmt.Sprintf("MixFetch API cannot load %s. Request mode is \"%s\" but the URL's origin is not same as the request origin %v.", req.Request.URL.String(), jstypes.ModeSameOrigin, jstypes.Origin())) } if req.Options.Mode == jstypes.ModeNoCors { if req.Options.Redirect != jstypes.RequestRedirectFollow { @@ -241,8 +241,17 @@ func doCorsCheck(reqOpts *types.RequestOptions, resp *http.Response) error { // 4.9.4 // TODO: presumably this needs to better account for the wildcard? - if jstypes.Origin() != originHeader { - return errors.New(fmt.Sprintf("\"%s\" does not match the origin \"%s\" on \"%s\" remote header", jstypes.Origin, originHeader, jstypes.HeaderAllowOrigin)) + + // if origin is null it means 4.9.2 would have failed anyway + origin := jstypes.Origin() + if origin == nil { + // TODO: won't this essentially fail all node requests? + return errors.New("the local origin is null") + } + + // safety: it's fine to dereference the pointer here as we've just checked if it's null + if *origin != originHeader { + return errors.New(fmt.Sprintf("\"%v\" does not match the origin \"%s\" on \"%s\" remote header", jstypes.Origin(), originHeader, jstypes.HeaderAllowOrigin)) } // 4.9.5 diff --git a/wasm/node-tester/Cargo.toml b/wasm/node-tester/Cargo.toml index d435a0e728..6a3d8126e7 100644 --- a/wasm/node-tester/Cargo.toml +++ b/wasm/node-tester/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nym-node-tester-wasm" authors = ["Jedrzej Stuczynski "] -version = "1.2.4-rc.1" +version = "1.2.4-rc.2" edition = "2021" keywords = ["nym", "sphinx", "webassembly", "privacy", "tester"] license = "Apache-2.0"