@kattebak/openapi-generator-ts 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +189 -0
- package/dist/cli/commands/generate.d.ts +23 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +116 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/list.d.ts +2 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +26 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +6 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +80 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/convert-template.d.ts +31 -0
- package/dist/cli/convert-template.d.ts.map +1 -0
- package/dist/cli/convert-template.js +204 -0
- package/dist/cli/convert-template.js.map +1 -0
- package/dist/cli/convert-template.test.d.ts +2 -0
- package/dist/cli/convert-template.test.d.ts.map +1 -0
- package/dist/cli/convert-template.test.js +74 -0
- package/dist/cli/convert-template.test.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +246 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/config.d.ts +252 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +31 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/generator.d.ts +99 -0
- package/dist/core/generator.d.ts.map +1 -0
- package/dist/core/generator.js +492 -0
- package/dist/core/generator.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/types.d.ts +47 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/generators/generators.test.d.ts +6 -0
- package/dist/generators/generators.test.d.ts.map +1 -0
- package/dist/generators/generators.test.js +247 -0
- package/dist/generators/generators.test.js.map +1 -0
- package/dist/generators/go.d.ts +10 -0
- package/dist/generators/go.d.ts.map +1 -0
- package/dist/generators/go.js +327 -0
- package/dist/generators/go.js.map +1 -0
- package/dist/generators/index.d.ts +29 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +58 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/php.d.ts +14 -0
- package/dist/generators/php.d.ts.map +1 -0
- package/dist/generators/php.js +241 -0
- package/dist/generators/php.js.map +1 -0
- package/dist/generators/python.d.ts +10 -0
- package/dist/generators/python.d.ts.map +1 -0
- package/dist/generators/python.js +273 -0
- package/dist/generators/python.js.map +1 -0
- package/dist/generators/typescript-fetch.d.ts +14 -0
- package/dist/generators/typescript-fetch.d.ts.map +1 -0
- package/dist/generators/typescript-fetch.js +217 -0
- package/dist/generators/typescript-fetch.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/models/codegen-model.d.ts +123 -0
- package/dist/models/codegen-model.d.ts.map +1 -0
- package/dist/models/codegen-model.js +64 -0
- package/dist/models/codegen-model.js.map +1 -0
- package/dist/models/codegen-model.test.d.ts +6 -0
- package/dist/models/codegen-model.test.d.ts.map +1 -0
- package/dist/models/codegen-model.test.js +143 -0
- package/dist/models/codegen-model.test.js.map +1 -0
- package/dist/models/codegen-operation.d.ts +95 -0
- package/dist/models/codegen-operation.d.ts.map +1 -0
- package/dist/models/codegen-operation.js +54 -0
- package/dist/models/codegen-operation.js.map +1 -0
- package/dist/models/codegen-parameter.d.ts +86 -0
- package/dist/models/codegen-parameter.d.ts.map +1 -0
- package/dist/models/codegen-parameter.js +47 -0
- package/dist/models/codegen-parameter.js.map +1 -0
- package/dist/models/codegen-property.d.ts +95 -0
- package/dist/models/codegen-property.d.ts.map +1 -0
- package/dist/models/codegen-property.js +47 -0
- package/dist/models/codegen-property.js.map +1 -0
- package/dist/models/codegen-response.d.ts +64 -0
- package/dist/models/codegen-response.d.ts.map +1 -0
- package/dist/models/codegen-response.js +42 -0
- package/dist/models/codegen-response.js.map +1 -0
- package/dist/models/codegen-security.d.ts +34 -0
- package/dist/models/codegen-security.d.ts.map +1 -0
- package/dist/models/codegen-security.js +18 -0
- package/dist/models/codegen-security.js.map +1 -0
- package/dist/models/index.d.ts +8 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +7 -0
- package/dist/models/index.js.map +1 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +4 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/openapi-parser.d.ts +71 -0
- package/dist/parser/openapi-parser.d.ts.map +1 -0
- package/dist/parser/openapi-parser.js +195 -0
- package/dist/parser/openapi-parser.js.map +1 -0
- package/dist/parser/openapi-parser.test.d.ts +6 -0
- package/dist/parser/openapi-parser.test.d.ts.map +1 -0
- package/dist/parser/openapi-parser.test.js +238 -0
- package/dist/parser/openapi-parser.test.js.map +1 -0
- package/dist/parser/operation-transformer.d.ts +95 -0
- package/dist/parser/operation-transformer.d.ts.map +1 -0
- package/dist/parser/operation-transformer.js +634 -0
- package/dist/parser/operation-transformer.js.map +1 -0
- package/dist/parser/schema-transformer.d.ts +134 -0
- package/dist/parser/schema-transformer.d.ts.map +1 -0
- package/dist/parser/schema-transformer.js +557 -0
- package/dist/parser/schema-transformer.js.map +1 -0
- package/dist/template/engine-adapter.d.ts +55 -0
- package/dist/template/engine-adapter.d.ts.map +1 -0
- package/dist/template/engine-adapter.js +178 -0
- package/dist/template/engine-adapter.js.map +1 -0
- package/dist/template/engine-adapter.test.d.ts +6 -0
- package/dist/template/engine-adapter.test.d.ts.map +1 -0
- package/dist/template/engine-adapter.test.js +186 -0
- package/dist/template/engine-adapter.test.js.map +1 -0
- package/dist/template/index.d.ts +5 -0
- package/dist/template/index.d.ts.map +1 -0
- package/dist/template/index.js +5 -0
- package/dist/template/index.js.map +1 -0
- package/dist/template/lambdas/indent-lambdas.d.ts +40 -0
- package/dist/template/lambdas/indent-lambdas.d.ts.map +1 -0
- package/dist/template/lambdas/indent-lambdas.js +98 -0
- package/dist/template/lambdas/indent-lambdas.js.map +1 -0
- package/dist/template/lambdas/index.d.ts +44 -0
- package/dist/template/lambdas/index.d.ts.map +1 -0
- package/dist/template/lambdas/index.js +79 -0
- package/dist/template/lambdas/index.js.map +1 -0
- package/dist/template/lambdas/string-lambdas.d.ts +78 -0
- package/dist/template/lambdas/string-lambdas.d.ts.map +1 -0
- package/dist/template/lambdas/string-lambdas.js +148 -0
- package/dist/template/lambdas/string-lambdas.js.map +1 -0
- package/dist/template/lambdas/string-lambdas.test.d.ts +6 -0
- package/dist/template/lambdas/string-lambdas.test.d.ts.map +1 -0
- package/dist/template/lambdas/string-lambdas.test.js +158 -0
- package/dist/template/lambdas/string-lambdas.test.js.map +1 -0
- package/dist/template/template-locator.d.ts +72 -0
- package/dist/template/template-locator.d.ts.map +1 -0
- package/dist/template/template-locator.js +173 -0
- package/dist/template/template-locator.js.map +1 -0
- package/dist/template/template-manager.d.ts +65 -0
- package/dist/template/template-manager.d.ts.map +1 -0
- package/dist/template/template-manager.js +185 -0
- package/dist/template/template-manager.js.map +1 -0
- package/package.json +67 -0
- package/templates/go/.travis.yml +8 -0
- package/templates/go/README.mustache +236 -0
- package/templates/go/api.mustache +452 -0
- package/templates/go/api_doc.mustache +92 -0
- package/templates/go/api_test.mustache +59 -0
- package/templates/go/client.mustache +761 -0
- package/templates/go/configuration.mustache +332 -0
- package/templates/go/git_push.sh.mustache +57 -0
- package/templates/go/gitignore.mustache +24 -0
- package/templates/go/go.mod.mustache +16 -0
- package/templates/go/go.sum.mustache +19 -0
- package/templates/go/model.mustache +21 -0
- package/templates/go/model_anyof.mustache +93 -0
- package/templates/go/model_doc.mustache +97 -0
- package/templates/go/model_enum.mustache +101 -0
- package/templates/go/model_oneof.mustache +160 -0
- package/templates/go/model_simple.mustache +572 -0
- package/templates/go/nullable_model.mustache +35 -0
- package/templates/go/openapi.mustache +1 -0
- package/templates/go/partial_header.mustache +18 -0
- package/templates/go/response.mustache +38 -0
- package/templates/go/signing.mustache +453 -0
- package/templates/go/utils.mustache +352 -0
- package/templates/php/.php-cs-fixer.dist.php +29 -0
- package/templates/php/.travis.yml +8 -0
- package/templates/php/ApiException.mustache +111 -0
- package/templates/php/Configuration.mustache +606 -0
- package/templates/php/FormDataProcessor.mustache +238 -0
- package/templates/php/HeaderSelector.mustache +265 -0
- package/templates/php/ModelInterface.mustache +103 -0
- package/templates/php/ObjectSerializer.mustache +591 -0
- package/templates/php/README.mustache +151 -0
- package/templates/php/api.mustache +891 -0
- package/templates/php/api_doc.mustache +105 -0
- package/templates/php/api_test.mustache +80 -0
- package/templates/php/composer.mustache +44 -0
- package/templates/php/git_push.sh.mustache +57 -0
- package/templates/php/gitignore +15 -0
- package/templates/php/libraries/psr-18/ApiException.mustache +114 -0
- package/templates/php/libraries/psr-18/DebugPlugin.mustache +93 -0
- package/templates/php/libraries/psr-18/README.mustache +161 -0
- package/templates/php/libraries/psr-18/api.mustache +833 -0
- package/templates/php/libraries/psr-18/api_doc.mustache +79 -0
- package/templates/php/libraries/psr-18/composer.mustache +56 -0
- package/templates/php/model.mustache +47 -0
- package/templates/php/model_doc.mustache +10 -0
- package/templates/php/model_enum.mustache +33 -0
- package/templates/php/model_generic.mustache +565 -0
- package/templates/php/model_test.mustache +88 -0
- package/templates/php/partial_header.mustache +18 -0
- package/templates/php/php_doc_auth_partial.mustache +23 -0
- package/templates/php/phpunit.xml.mustache +18 -0
- package/templates/python/README.mustache +60 -0
- package/templates/python/README_onlypackage.mustache +50 -0
- package/templates/python/__init__.mustache +1 -0
- package/templates/python/__init__api.mustache +19 -0
- package/templates/python/__init__model.mustache +22 -0
- package/templates/python/__init__package.mustache +49 -0
- package/templates/python/api.mustache +244 -0
- package/templates/python/api_client.mustache +822 -0
- package/templates/python/api_doc.mustache +81 -0
- package/templates/python/api_doc_example.mustache +38 -0
- package/templates/python/api_response.mustache +21 -0
- package/templates/python/api_test.mustache +48 -0
- package/templates/python/asyncio/rest.mustache +209 -0
- package/templates/python/common_README.mustache +85 -0
- package/templates/python/configuration.mustache +806 -0
- package/templates/python/exceptions.mustache +210 -0
- package/templates/python/exports_api.mustache +3 -0
- package/templates/python/exports_model.mustache +3 -0
- package/templates/python/exports_package.mustache +20 -0
- package/templates/python/git_push.sh.mustache +57 -0
- package/templates/python/github-workflow.mustache +35 -0
- package/templates/python/gitignore.mustache +66 -0
- package/templates/python/gitlab-ci.mustache +31 -0
- package/templates/python/httpx/rest.mustache +190 -0
- package/templates/python/model.mustache +16 -0
- package/templates/python/model_anyof.mustache +182 -0
- package/templates/python/model_doc.mustache +40 -0
- package/templates/python/model_enum.mustache +36 -0
- package/templates/python/model_generic.mustache +403 -0
- package/templates/python/model_oneof.mustache +209 -0
- package/templates/python/model_test.mustache +60 -0
- package/templates/python/partial_api.mustache +52 -0
- package/templates/python/partial_api_args.mustache +18 -0
- package/templates/python/partial_header.mustache +19 -0
- package/templates/python/py.typed.mustache +1 -0
- package/templates/python/pyproject.mustache +172 -0
- package/templates/python/python_doc_auth_partial.mustache +108 -0
- package/templates/python/requirements.mustache +23 -0
- package/templates/python/rest.mustache +254 -0
- package/templates/python/setup.mustache +60 -0
- package/templates/python/setup_cfg.mustache +2 -0
- package/templates/python/signing.mustache +422 -0
- package/templates/python/test-requirements.mustache +6 -0
- package/templates/python/tornado/rest.mustache +148 -0
- package/templates/python/tox.mustache +9 -0
- package/templates/python/travis.mustache +17 -0
- package/templates/typescript-fetch/ApiEntitiesRecord.mustache +26 -0
- package/templates/typescript-fetch/ApiEntitiesReducer.mustache +21 -0
- package/templates/typescript-fetch/ApiEntitiesSelectors.mustache +5 -0
- package/templates/typescript-fetch/README.mustache +127 -0
- package/templates/typescript-fetch/allSagas.mustache +19 -0
- package/templates/typescript-fetch/api_doc.mustache +63 -0
- package/templates/typescript-fetch/api_example.mustache +44 -0
- package/templates/typescript-fetch/apis.index.mustache +16 -0
- package/templates/typescript-fetch/apis.mustache +483 -0
- package/templates/typescript-fetch/apisAssignQueryParam.mustache +12 -0
- package/templates/typescript-fetch/gitignore +4 -0
- package/templates/typescript-fetch/index.mustache +17 -0
- package/templates/typescript-fetch/licenseInfo.mustache +11 -0
- package/templates/typescript-fetch/modelEnum.mustache +28 -0
- package/templates/typescript-fetch/modelEnumInterfaces.mustache +37 -0
- package/templates/typescript-fetch/modelGeneric.mustache +261 -0
- package/templates/typescript-fetch/modelGenericInterfaces.mustache +50 -0
- package/templates/typescript-fetch/modelOneOf.mustache +255 -0
- package/templates/typescript-fetch/modelOneOfInterfaces.mustache +6 -0
- package/templates/typescript-fetch/model_doc.mustache +41 -0
- package/templates/typescript-fetch/models.index.mustache +32 -0
- package/templates/typescript-fetch/models.mustache +24 -0
- package/templates/typescript-fetch/npmignore.mustache +1 -0
- package/templates/typescript-fetch/package.mustache +43 -0
- package/templates/typescript-fetch/recordGeneric.mustache +295 -0
- package/templates/typescript-fetch/records.mustache +17 -0
- package/templates/typescript-fetch/runtime.mustache +424 -0
- package/templates/typescript-fetch/runtimeSagasAndRecords.mustache +120 -0
- package/templates/typescript-fetch/sagaApiManager.mustache +28 -0
- package/templates/typescript-fetch/sagas.mustache +245 -0
- package/templates/typescript-fetch/sourceLibraryIndex.mustache +1 -0
- package/templates/typescript-fetch/tsconfig.esm.mustache +7 -0
- package/templates/typescript-fetch/tsconfig.mustache +25 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
{{>partial_header}}
|
|
2
|
+
package {{packageName}}
|
|
3
|
+
|
|
4
|
+
import (
|
|
5
|
+
"bytes"
|
|
6
|
+
"context"
|
|
7
|
+
"crypto"
|
|
8
|
+
"crypto/ecdsa"
|
|
9
|
+
"crypto/ed25519"
|
|
10
|
+
"crypto/rand"
|
|
11
|
+
"crypto/rsa"
|
|
12
|
+
"crypto/x509"
|
|
13
|
+
"encoding/base64"
|
|
14
|
+
"encoding/pem"
|
|
15
|
+
"fmt"
|
|
16
|
+
"io"
|
|
17
|
+
"net/http"
|
|
18
|
+
"net/textproto"
|
|
19
|
+
"os"
|
|
20
|
+
"strings"
|
|
21
|
+
"time"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const (
|
|
25
|
+
// Constants for HTTP signature parameters.
|
|
26
|
+
// The '(request-target)' parameter concatenates the lowercased :method, an
|
|
27
|
+
// ASCII space, and the :path pseudo-headers.
|
|
28
|
+
HttpSignatureParameterRequestTarget string = "(request-target)"
|
|
29
|
+
// The '(created)' parameter expresses when the signature was
|
|
30
|
+
// created. The value MUST be a Unix timestamp integer value.
|
|
31
|
+
HttpSignatureParameterCreated string = "(created)"
|
|
32
|
+
// The '(expires)' parameter expresses when the signature ceases to
|
|
33
|
+
// be valid. The value MUST be a Unix timestamp integer value.
|
|
34
|
+
HttpSignatureParameterExpires string = "(expires)"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const (
|
|
38
|
+
// Constants for HTTP headers.
|
|
39
|
+
// The 'Host' header, as defined in RFC 2616, section 14.[23].
|
|
40
|
+
HttpHeaderHost string = "Host"
|
|
41
|
+
// The 'Date' header.
|
|
42
|
+
HttpHeaderDate string = "Date"
|
|
43
|
+
// The digest header, as defined in RFC 3230, section 4.[3].2.
|
|
44
|
+
HttpHeaderDigest string = "Digest"
|
|
45
|
+
// The HTTP Authorization header, as defined in RFC 7235, section 4.[2].
|
|
46
|
+
HttpHeaderAuthorization string = "Authorization"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const (
|
|
50
|
+
// Specifies the Digital Signature Algorithm is derived from metadata
|
|
51
|
+
// associated with 'keyId'. Supported DSA algorithms are RSASSA-PKCS1-v1_5,
|
|
52
|
+
// RSASSA-PSS, and ECDSA.
|
|
53
|
+
// The hash is SHA-512.
|
|
54
|
+
// This is the default value.
|
|
55
|
+
HttpSigningSchemeHs2019 string = "hs2019"
|
|
56
|
+
// Use RSASSA-PKCS1-v1_5 with SHA-512 hash. Deprecated.
|
|
57
|
+
HttpSigningSchemeRsaSha512 string = "rsa-sha512"
|
|
58
|
+
// Use RSASSA-PKCS1-v1_5 with SHA-256 hash. Deprecated.
|
|
59
|
+
HttpSigningSchemeRsaSha256 string = "rsa-sha256"
|
|
60
|
+
|
|
61
|
+
// RFC 8017 section 7.2
|
|
62
|
+
// Calculate the message signature using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.[5].
|
|
63
|
+
// PKCSV1_5 is deterministic. The same message and key will produce an identical
|
|
64
|
+
// signature value each time.
|
|
65
|
+
HttpSigningAlgorithmRsaPKCS1v15 string = "RSASSA-PKCS1-v1_5"
|
|
66
|
+
// Calculate the message signature using probabilistic signature scheme RSASSA-PSS.
|
|
67
|
+
// PSS is randomized and will produce a different signature value each time.
|
|
68
|
+
HttpSigningAlgorithmRsaPSS string = "RSASSA-PSS"
|
|
69
|
+
|
|
70
|
+
// HashAlgorithm Sha256 for generating hash
|
|
71
|
+
HttpHashAlgorithmSha256 string = "sha256"
|
|
72
|
+
|
|
73
|
+
// HashAlgorithm Sha512 for generating hash
|
|
74
|
+
HttpHashAlgorithmSha512 string = "sha512"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
var supportedSigningSchemes = map[string]bool{
|
|
78
|
+
HttpSigningSchemeHs2019: true,
|
|
79
|
+
HttpSigningSchemeRsaSha512: true,
|
|
80
|
+
HttpSigningSchemeRsaSha256: true,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
// HttpSignatureAuth provides HTTP signature authentication to a request passed
|
|
85
|
+
// via context using ContextHttpSignatureAuth.
|
|
86
|
+
// An 'Authorization' header is calculated by creating a hash of select headers,
|
|
87
|
+
// and optionally the body of the HTTP request, then signing the hash value using
|
|
88
|
+
// a private key which is available to the client.
|
|
89
|
+
//
|
|
90
|
+
// SignedHeaders specifies the list of HTTP headers that are included when generating
|
|
91
|
+
// the message signature.
|
|
92
|
+
// The two special signature headers '(request-target)' and '(created)' SHOULD be
|
|
93
|
+
// included in SignedHeaders.
|
|
94
|
+
// The '(created)' header expresses when the signature was created.
|
|
95
|
+
// The '(request-target)' header is a concatenation of the lowercased :method, an
|
|
96
|
+
// ASCII space, and the :path pseudo-headers.
|
|
97
|
+
//
|
|
98
|
+
// For example, SignedHeaders can be set to:
|
|
99
|
+
// (request-target) (created) date host digest
|
|
100
|
+
//
|
|
101
|
+
// When SignedHeaders is not specified, the client defaults to a single value, '(created)',
|
|
102
|
+
// in the list of HTTP headers.
|
|
103
|
+
// When SignedHeaders contains the 'Digest' value, the client performs the following operations:
|
|
104
|
+
// 1. Calculate a digest of request body, as specified in RFC3230, section 4.[3].2.
|
|
105
|
+
// 2. Set the 'Digest' header in the request body.
|
|
106
|
+
// 3. Include the 'Digest' header and value in the HTTP signature.
|
|
107
|
+
type HttpSignatureAuth struct {
|
|
108
|
+
KeyId string // A key identifier.
|
|
109
|
+
PrivateKeyPath string // The path to the private key.
|
|
110
|
+
PrivateKeyReader io.Reader // provide the APIKey using the types which implement io.Reader interface.
|
|
111
|
+
Passphrase string // The passphrase to decrypt the private key, if the key is encrypted.
|
|
112
|
+
SigningScheme string // The signature scheme, when signing HTTP requests. Supported value is 'hs2019'.
|
|
113
|
+
// The signature algorithm, when signing HTTP requests.
|
|
114
|
+
// Supported values are RSASSA-PKCS1-v1_5, RSASSA-PSS.
|
|
115
|
+
SigningAlgorithm string
|
|
116
|
+
HashAlgorithm string // supported values are sha256 and sha512. This also allows using sha256 with hs2019, which defaults to sha512.
|
|
117
|
+
SignedHeaders []string // A list of HTTP headers included when generating the signature for the message.
|
|
118
|
+
// SignatureMaxValidity specifies the maximum duration of the signature validity.
|
|
119
|
+
// The value is used to set the '(expires)' signature parameter in the HTTP request.
|
|
120
|
+
// '(expires)' is set to '(created)' plus the value of the SignatureMaxValidity field.
|
|
121
|
+
// To specify the '(expires)' signature parameter, set 'SignatureMaxValidity' and add '(expires)' to 'SignedHeaders'.
|
|
122
|
+
SignatureMaxValidity time.Duration
|
|
123
|
+
privateKey crypto.PrivateKey // The private key used to sign HTTP requests.
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// SetPrivateKey accepts a private key string and sets it.
|
|
127
|
+
func (h *HttpSignatureAuth) SetPrivateKey(privateKey string) error {
|
|
128
|
+
return h.parsePrivateKey([]byte(privateKey))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ContextWithValue validates the HttpSignatureAuth configuration parameters and returns a context
|
|
132
|
+
// suitable for HTTP signature. An error is returned if the HttpSignatureAuth configuration parameters
|
|
133
|
+
// are invalid.
|
|
134
|
+
func (h *HttpSignatureAuth) ContextWithValue(ctx context.Context) (context.Context, error) {
|
|
135
|
+
if h.KeyId == "" {
|
|
136
|
+
return nil, fmt.Errorf("key ID must be specified")
|
|
137
|
+
}
|
|
138
|
+
if (len(h.PrivateKeyPath) == 0 && h.PrivateKeyReader == nil) && h.privateKey == nil {
|
|
139
|
+
return nil, fmt.Errorf("private key path must be specified")
|
|
140
|
+
}
|
|
141
|
+
if len(h.PrivateKeyPath) > 0 && h.PrivateKeyReader != nil{
|
|
142
|
+
return nil, fmt.Errorf("Specify only one of PrivateKeyPath or PrivateKeyReader")
|
|
143
|
+
}
|
|
144
|
+
if _, ok := supportedSigningSchemes[h.SigningScheme]; !ok {
|
|
145
|
+
return nil, fmt.Errorf("invalid signing scheme: '%v'", h.SigningScheme)
|
|
146
|
+
}
|
|
147
|
+
m := make(map[string]bool)
|
|
148
|
+
for _, h := range h.SignedHeaders {
|
|
149
|
+
if strings.EqualFold(h, HttpHeaderAuthorization) {
|
|
150
|
+
return nil, fmt.Errorf("signed headers cannot include the 'Authorization' header")
|
|
151
|
+
}
|
|
152
|
+
m[h] = true
|
|
153
|
+
}
|
|
154
|
+
if len(m) != len(h.SignedHeaders) {
|
|
155
|
+
return nil, fmt.Errorf("list of signed headers cannot have duplicate names")
|
|
156
|
+
}
|
|
157
|
+
if h.SignatureMaxValidity < 0 {
|
|
158
|
+
return nil, fmt.Errorf("signature max validity must be a positive value")
|
|
159
|
+
}
|
|
160
|
+
if err := h.loadPrivateKey(); err != nil {
|
|
161
|
+
return nil, err
|
|
162
|
+
}
|
|
163
|
+
return context.WithValue(ctx, ContextHttpSignatureAuth, *h), nil
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// GetPublicKey returns the public key associated with this HTTP signature configuration.
|
|
167
|
+
func (h *HttpSignatureAuth) GetPublicKey() (crypto.PublicKey, error) {
|
|
168
|
+
if h.privateKey == nil {
|
|
169
|
+
if err := h.loadPrivateKey(); err != nil {
|
|
170
|
+
return nil, err
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
switch key := h.privateKey.(type) {
|
|
174
|
+
case *rsa.PrivateKey:
|
|
175
|
+
return key.Public(), nil
|
|
176
|
+
case *ecdsa.PrivateKey:
|
|
177
|
+
return key.Public(), nil
|
|
178
|
+
default:
|
|
179
|
+
// Do not change '%T' to anything else such as '%v'!
|
|
180
|
+
// The value of the private key must not be returned.
|
|
181
|
+
return nil, fmt.Errorf("unsupported key: %T", h.privateKey)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// loadPrivateKey reads the private key from the file specified in the HttpSignatureAuth.
|
|
186
|
+
// The key is loaded only when privateKey is not already set.
|
|
187
|
+
func (h *HttpSignatureAuth) loadPrivateKey() (err error) {
|
|
188
|
+
if h.privateKey != nil {
|
|
189
|
+
return nil
|
|
190
|
+
}
|
|
191
|
+
var priv []byte
|
|
192
|
+
keyReader := h.PrivateKeyReader
|
|
193
|
+
if keyReader == nil {
|
|
194
|
+
var file *os.File
|
|
195
|
+
file, err = os.Open(h.PrivateKeyPath)
|
|
196
|
+
if err != nil {
|
|
197
|
+
return fmt.Errorf("cannot load private key '%s'. Error: %v", h.PrivateKeyPath, err)
|
|
198
|
+
}
|
|
199
|
+
keyReader = file
|
|
200
|
+
defer func() {
|
|
201
|
+
err = file.Close()
|
|
202
|
+
}()
|
|
203
|
+
}
|
|
204
|
+
priv, err = io.ReadAll(keyReader)
|
|
205
|
+
if err != nil{
|
|
206
|
+
return err
|
|
207
|
+
}
|
|
208
|
+
return h.parsePrivateKey(priv)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// parsePrivateKey decodes privateKey byte array to crypto.PrivateKey type.
|
|
212
|
+
func (h *HttpSignatureAuth) parsePrivateKey(priv []byte) error {
|
|
213
|
+
pemBlock, _ := pem.Decode(priv)
|
|
214
|
+
if pemBlock == nil {
|
|
215
|
+
// No PEM data has been found.
|
|
216
|
+
return fmt.Errorf("file '%s' does not contain PEM data", h.PrivateKeyPath)
|
|
217
|
+
}
|
|
218
|
+
var privKey []byte
|
|
219
|
+
var err error
|
|
220
|
+
if x509.IsEncryptedPEMBlock(pemBlock) {
|
|
221
|
+
// The PEM data is encrypted.
|
|
222
|
+
privKey, err = x509.DecryptPEMBlock(pemBlock, []byte(h.Passphrase))
|
|
223
|
+
if err != nil {
|
|
224
|
+
// Failed to decrypt PEM block. Because of deficiencies in the encrypted-PEM format,
|
|
225
|
+
// it's not always possible to detect an incorrect password.
|
|
226
|
+
return err
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
privKey = pemBlock.Bytes
|
|
230
|
+
}
|
|
231
|
+
switch pemBlock.Type {
|
|
232
|
+
case "RSA PRIVATE KEY":
|
|
233
|
+
if h.privateKey, err = x509.ParsePKCS1PrivateKey(privKey); err != nil {
|
|
234
|
+
return err
|
|
235
|
+
}
|
|
236
|
+
case "EC PRIVATE KEY", "PRIVATE KEY":
|
|
237
|
+
// https://tools.ietf.org/html/rfc5915 section 4.
|
|
238
|
+
if h.privateKey, err = x509.ParsePKCS8PrivateKey(privKey); err != nil {
|
|
239
|
+
return err
|
|
240
|
+
}
|
|
241
|
+
default:
|
|
242
|
+
return fmt.Errorf("key '%s' is not supported", pemBlock.Type)
|
|
243
|
+
}
|
|
244
|
+
return nil
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// SignRequest signs the request using HTTP signature.
|
|
248
|
+
// See https://datatracker.ietf.org/doc/draft-cavage-http-signatures/
|
|
249
|
+
//
|
|
250
|
+
// Do not add, remove or change headers that are included in the SignedHeaders
|
|
251
|
+
// after SignRequest has been invoked; this is because the header values are
|
|
252
|
+
// included in the signature. Any subsequent alteration will cause a signature
|
|
253
|
+
// verification failure.
|
|
254
|
+
// If there are multiple instances of the same header field, all
|
|
255
|
+
// header field values associated with the header field MUST be
|
|
256
|
+
// concatenated, separated by a ASCII comma and an ASCII space
|
|
257
|
+
// ', ', and used in the order in which they will appear in the
|
|
258
|
+
// transmitted HTTP message.
|
|
259
|
+
func SignRequest(
|
|
260
|
+
ctx context.Context,
|
|
261
|
+
r *http.Request,
|
|
262
|
+
auth HttpSignatureAuth) error {
|
|
263
|
+
|
|
264
|
+
if auth.privateKey == nil {
|
|
265
|
+
return fmt.Errorf("private key is not set")
|
|
266
|
+
}
|
|
267
|
+
now := time.Now()
|
|
268
|
+
date := now.UTC().Format(http.TimeFormat)
|
|
269
|
+
// The 'created' field expresses when the signature was created.
|
|
270
|
+
// The value MUST be a Unix timestamp integer value. See 'HTTP signature' section 2.[1].4.
|
|
271
|
+
created := now.Unix()
|
|
272
|
+
|
|
273
|
+
var h crypto.Hash
|
|
274
|
+
var err error
|
|
275
|
+
var prefix string
|
|
276
|
+
var expiresUnix float64
|
|
277
|
+
|
|
278
|
+
if auth.SignatureMaxValidity < 0 {
|
|
279
|
+
return fmt.Errorf("signature validity must be a positive value")
|
|
280
|
+
}
|
|
281
|
+
if auth.SignatureMaxValidity > 0 {
|
|
282
|
+
e := now.Add(auth.SignatureMaxValidity)
|
|
283
|
+
expiresUnix = float64(e.Unix()) + float64(e.Nanosecond()) / float64(time.Second)
|
|
284
|
+
}
|
|
285
|
+
// Determine the cryptographic hash to be used for the signature and the body digest.
|
|
286
|
+
switch auth.SigningScheme {
|
|
287
|
+
case HttpSigningSchemeRsaSha512:
|
|
288
|
+
h = crypto.SHA512
|
|
289
|
+
prefix = "SHA-512="
|
|
290
|
+
case HttpSigningSchemeRsaSha256:
|
|
291
|
+
// This is deprecated and should no longer be used.
|
|
292
|
+
h = crypto.SHA256
|
|
293
|
+
prefix = "SHA-256="
|
|
294
|
+
case HttpSigningSchemeHs2019:
|
|
295
|
+
if auth.HashAlgorithm == HttpHashAlgorithmSha256 {
|
|
296
|
+
h = crypto.SHA256
|
|
297
|
+
prefix = "SHA-256="
|
|
298
|
+
} else {
|
|
299
|
+
h = crypto.SHA512
|
|
300
|
+
prefix = "SHA-512="
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
default:
|
|
304
|
+
return fmt.Errorf("unsupported signature scheme: %v", auth.SigningScheme)
|
|
305
|
+
}
|
|
306
|
+
if !h.Available() {
|
|
307
|
+
return fmt.Errorf("hash '%v' is not available", h)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Build the "(request-target)" signature header.
|
|
311
|
+
var sb bytes.Buffer
|
|
312
|
+
fmt.Fprintf(&sb, "%s %s", strings.ToLower(r.Method), r.URL.EscapedPath())
|
|
313
|
+
if r.URL.RawQuery != "" {
|
|
314
|
+
// The ":path" pseudo-header field includes the path and query parts
|
|
315
|
+
// of the target URI (the "path-absolute" production and optionally a
|
|
316
|
+
// '?' character followed by the "query" production (see Sections 3.3
|
|
317
|
+
// and 3.4 of [RFC3986]
|
|
318
|
+
fmt.Fprintf(&sb, "?%s", r.URL.RawQuery)
|
|
319
|
+
}
|
|
320
|
+
requestTarget := sb.String()
|
|
321
|
+
sb.Reset()
|
|
322
|
+
|
|
323
|
+
// Build the string to be signed.
|
|
324
|
+
signedHeaders := auth.SignedHeaders
|
|
325
|
+
if len(signedHeaders) == 0 {
|
|
326
|
+
signedHeaders = []string{HttpSignatureParameterCreated}
|
|
327
|
+
}
|
|
328
|
+
// Validate the list of signed headers has no duplicates.
|
|
329
|
+
m := make(map[string]bool)
|
|
330
|
+
for _, h := range signedHeaders {
|
|
331
|
+
m[h] = true
|
|
332
|
+
}
|
|
333
|
+
if len(m) != len(signedHeaders) {
|
|
334
|
+
return fmt.Errorf("list of signed headers must not have any duplicates")
|
|
335
|
+
}
|
|
336
|
+
hasCreatedParameter := false
|
|
337
|
+
hasExpiresParameter := false
|
|
338
|
+
for i, header := range signedHeaders {
|
|
339
|
+
header = strings.ToLower(header)
|
|
340
|
+
var value string
|
|
341
|
+
switch header {
|
|
342
|
+
case strings.ToLower(HttpHeaderAuthorization):
|
|
343
|
+
return fmt.Errorf("cannot include the 'Authorization' header as a signed header")
|
|
344
|
+
case HttpSignatureParameterRequestTarget:
|
|
345
|
+
value = requestTarget
|
|
346
|
+
case HttpSignatureParameterCreated:
|
|
347
|
+
value = fmt.Sprintf("%d", created)
|
|
348
|
+
hasCreatedParameter = true
|
|
349
|
+
case HttpSignatureParameterExpires:
|
|
350
|
+
if auth.SignatureMaxValidity.Nanoseconds() == 0 {
|
|
351
|
+
return fmt.Errorf("cannot set '(expires)' signature parameter. SignatureMaxValidity is not configured")
|
|
352
|
+
}
|
|
353
|
+
value = fmt.Sprintf("%.3f", expiresUnix)
|
|
354
|
+
hasExpiresParameter = true
|
|
355
|
+
case "date":
|
|
356
|
+
value = date
|
|
357
|
+
r.Header.Set(HttpHeaderDate, date)
|
|
358
|
+
case "digest":
|
|
359
|
+
// Calculate the digest of the HTTP request body.
|
|
360
|
+
// Calculate body digest per RFC 3230 section 4.[3].2
|
|
361
|
+
bodyHash := h.New()
|
|
362
|
+
if r.Body != nil {
|
|
363
|
+
// Make a copy of the body io.Reader so that we can read the body to calculate the hash,
|
|
364
|
+
// then one more time when marshaling the request.
|
|
365
|
+
var body io.Reader
|
|
366
|
+
body, err = r.GetBody()
|
|
367
|
+
if err != nil {
|
|
368
|
+
return err
|
|
369
|
+
}
|
|
370
|
+
if _, err = io.Copy(bodyHash, body); err != nil {
|
|
371
|
+
return err
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
d := bodyHash.Sum(nil)
|
|
375
|
+
value = prefix + base64.StdEncoding.EncodeToString(d)
|
|
376
|
+
r.Header.Set(HttpHeaderDigest, value)
|
|
377
|
+
case "host":
|
|
378
|
+
value = r.Host
|
|
379
|
+
r.Header.Set(HttpHeaderHost, r.Host)
|
|
380
|
+
default:
|
|
381
|
+
var ok bool
|
|
382
|
+
var v []string
|
|
383
|
+
canonicalHeader := textproto.CanonicalMIMEHeaderKey(header)
|
|
384
|
+
if v, ok = r.Header[canonicalHeader]; !ok {
|
|
385
|
+
// If a header specified in the headers parameter cannot be matched with
|
|
386
|
+
// a provided header in the message, the implementation MUST produce an error.
|
|
387
|
+
return fmt.Errorf("header '%s' does not exist in the request", canonicalHeader)
|
|
388
|
+
}
|
|
389
|
+
// If there are multiple instances of the same header field, all
|
|
390
|
+
// header field values associated with the header field MUST be
|
|
391
|
+
// concatenated, separated by a ASCII comma and an ASCII space
|
|
392
|
+
// `, `, and used in the order in which they will appear in the
|
|
393
|
+
// transmitted HTTP message.
|
|
394
|
+
value = strings.Join(v, ", ")
|
|
395
|
+
}
|
|
396
|
+
if i > 0 {
|
|
397
|
+
fmt.Fprintf(&sb, "\n")
|
|
398
|
+
}
|
|
399
|
+
fmt.Fprintf(&sb, "%s: %s", header, value)
|
|
400
|
+
}
|
|
401
|
+
if expiresUnix != 0 && !hasExpiresParameter {
|
|
402
|
+
return fmt.Errorf("signatureMaxValidity is specified, but '(expired)' parameter is not present")
|
|
403
|
+
}
|
|
404
|
+
msg := []byte(sb.String())
|
|
405
|
+
msgHash := h.New()
|
|
406
|
+
if _, err = msgHash.Write(msg); err != nil {
|
|
407
|
+
return err
|
|
408
|
+
}
|
|
409
|
+
d := msgHash.Sum(nil)
|
|
410
|
+
|
|
411
|
+
var signature []byte
|
|
412
|
+
switch key := auth.privateKey.(type) {
|
|
413
|
+
case *rsa.PrivateKey:
|
|
414
|
+
switch auth.SigningAlgorithm {
|
|
415
|
+
case HttpSigningAlgorithmRsaPKCS1v15:
|
|
416
|
+
signature, err = rsa.SignPKCS1v15(rand.Reader, key, h, d)
|
|
417
|
+
case "", HttpSigningAlgorithmRsaPSS:
|
|
418
|
+
signature, err = rsa.SignPSS(rand.Reader, key, h, d, nil)
|
|
419
|
+
default:
|
|
420
|
+
return fmt.Errorf("unsupported signing algorithm: '%s'", auth.SigningAlgorithm)
|
|
421
|
+
}
|
|
422
|
+
case *ecdsa.PrivateKey:
|
|
423
|
+
signature, err = key.Sign(rand.Reader, d, h)
|
|
424
|
+
case ed25519.PrivateKey: // requires go 1.13
|
|
425
|
+
signature, err = key.Sign(rand.Reader, msg, crypto.Hash(0))
|
|
426
|
+
default:
|
|
427
|
+
return fmt.Errorf("unsupported private key")
|
|
428
|
+
}
|
|
429
|
+
if err != nil {
|
|
430
|
+
return err
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
sb.Reset()
|
|
434
|
+
for i, header := range signedHeaders {
|
|
435
|
+
if i > 0 {
|
|
436
|
+
sb.WriteRune(' ')
|
|
437
|
+
}
|
|
438
|
+
sb.WriteString(strings.ToLower(header))
|
|
439
|
+
}
|
|
440
|
+
headers_list := sb.String()
|
|
441
|
+
sb.Reset()
|
|
442
|
+
fmt.Fprintf(&sb, `Signature keyId="%s",algorithm="%s",`, auth.KeyId, auth.SigningScheme)
|
|
443
|
+
if hasCreatedParameter {
|
|
444
|
+
fmt.Fprintf(&sb, "created=%d,", created)
|
|
445
|
+
}
|
|
446
|
+
if hasExpiresParameter {
|
|
447
|
+
fmt.Fprintf(&sb, "expires=%.3f,", expiresUnix)
|
|
448
|
+
}
|
|
449
|
+
fmt.Fprintf(&sb, `headers="%s",signature="%s"`, headers_list, base64.StdEncoding.EncodeToString(signature))
|
|
450
|
+
authStr := sb.String()
|
|
451
|
+
r.Header.Set(HttpHeaderAuthorization, authStr)
|
|
452
|
+
return nil
|
|
453
|
+
}
|