euclid-ndk 0.2.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.
Files changed (127) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +603 -0
  3. package/dist/auth/index.d.ts +18 -0
  4. package/dist/auth/index.d.ts.map +1 -0
  5. package/dist/auth/index.js +17 -0
  6. package/dist/auth/index.js.map +1 -0
  7. package/dist/auth/rfc9421.d.ts +112 -0
  8. package/dist/auth/rfc9421.d.ts.map +1 -0
  9. package/dist/auth/rfc9421.js +452 -0
  10. package/dist/auth/rfc9421.js.map +1 -0
  11. package/dist/auth/scheme.d.ts +46 -0
  12. package/dist/auth/scheme.d.ts.map +1 -0
  13. package/dist/auth/scheme.js +44 -0
  14. package/dist/auth/scheme.js.map +1 -0
  15. package/dist/auth/signable.d.ts +37 -0
  16. package/dist/auth/signable.d.ts.map +1 -0
  17. package/dist/auth/signable.js +70 -0
  18. package/dist/auth/signable.js.map +1 -0
  19. package/dist/auth/sigv4.d.ts +72 -0
  20. package/dist/auth/sigv4.d.ts.map +1 -0
  21. package/dist/auth/sigv4.js +227 -0
  22. package/dist/auth/sigv4.js.map +1 -0
  23. package/dist/credentials.d.ts +56 -0
  24. package/dist/credentials.d.ts.map +1 -0
  25. package/dist/credentials.js +135 -0
  26. package/dist/credentials.js.map +1 -0
  27. package/dist/dto/com.d.ts +101 -0
  28. package/dist/dto/com.d.ts.map +1 -0
  29. package/dist/dto/com.js +132 -0
  30. package/dist/dto/com.js.map +1 -0
  31. package/dist/dto/eag.d.ts +104 -0
  32. package/dist/dto/eag.d.ts.map +1 -0
  33. package/dist/dto/eag.js +70 -0
  34. package/dist/dto/eag.js.map +1 -0
  35. package/dist/dto/eam.d.ts +105 -0
  36. package/dist/dto/eam.d.ts.map +1 -0
  37. package/dist/dto/eam.js +98 -0
  38. package/dist/dto/eam.js.map +1 -0
  39. package/dist/dto/eap.d.ts +88 -0
  40. package/dist/dto/eap.d.ts.map +1 -0
  41. package/dist/dto/eap.js +54 -0
  42. package/dist/dto/eap.js.map +1 -0
  43. package/dist/dto/ekm.d.ts +109 -0
  44. package/dist/dto/ekm.d.ts.map +1 -0
  45. package/dist/dto/ekm.js +78 -0
  46. package/dist/dto/ekm.js.map +1 -0
  47. package/dist/dto/ekv.d.ts +73 -0
  48. package/dist/dto/ekv.d.ts.map +1 -0
  49. package/dist/dto/ekv.js +45 -0
  50. package/dist/dto/ekv.js.map +1 -0
  51. package/dist/dto/ens.d.ts +84 -0
  52. package/dist/dto/ens.d.ts.map +1 -0
  53. package/dist/dto/ens.js +72 -0
  54. package/dist/dto/ens.js.map +1 -0
  55. package/dist/dto/eqs.d.ts +160 -0
  56. package/dist/dto/eqs.d.ts.map +1 -0
  57. package/dist/dto/eqs.js +120 -0
  58. package/dist/dto/eqs.js.map +1 -0
  59. package/dist/dto/esm.d.ts +192 -0
  60. package/dist/dto/esm.d.ts.map +1 -0
  61. package/dist/dto/esm.js +147 -0
  62. package/dist/dto/esm.js.map +1 -0
  63. package/dist/dto/ess.d.ts +49 -0
  64. package/dist/dto/ess.d.ts.map +1 -0
  65. package/dist/dto/ess.js +30 -0
  66. package/dist/dto/ess.js.map +1 -0
  67. package/dist/dto/json.d.ts +24 -0
  68. package/dist/dto/json.d.ts.map +1 -0
  69. package/dist/dto/json.js +47 -0
  70. package/dist/dto/json.js.map +1 -0
  71. package/dist/errors.d.ts +40 -0
  72. package/dist/errors.d.ts.map +1 -0
  73. package/dist/errors.js +73 -0
  74. package/dist/errors.js.map +1 -0
  75. package/dist/http/client.d.ts +96 -0
  76. package/dist/http/client.d.ts.map +1 -0
  77. package/dist/http/client.js +258 -0
  78. package/dist/http/client.js.map +1 -0
  79. package/dist/index.d.ts +93 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +110 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/modules/base.d.ts +121 -0
  84. package/dist/modules/base.d.ts.map +1 -0
  85. package/dist/modules/base.js +142 -0
  86. package/dist/modules/base.js.map +1 -0
  87. package/dist/modules/eag.d.ts +166 -0
  88. package/dist/modules/eag.d.ts.map +1 -0
  89. package/dist/modules/eag.js +189 -0
  90. package/dist/modules/eag.js.map +1 -0
  91. package/dist/modules/eam.d.ts +314 -0
  92. package/dist/modules/eam.d.ts.map +1 -0
  93. package/dist/modules/eam.js +641 -0
  94. package/dist/modules/eam.js.map +1 -0
  95. package/dist/modules/eap.d.ts +204 -0
  96. package/dist/modules/eap.d.ts.map +1 -0
  97. package/dist/modules/eap.js +218 -0
  98. package/dist/modules/eap.js.map +1 -0
  99. package/dist/modules/ekm.d.ts +182 -0
  100. package/dist/modules/ekm.d.ts.map +1 -0
  101. package/dist/modules/ekm.js +228 -0
  102. package/dist/modules/ekm.js.map +1 -0
  103. package/dist/modules/ekv.d.ts +189 -0
  104. package/dist/modules/ekv.d.ts.map +1 -0
  105. package/dist/modules/ekv.js +212 -0
  106. package/dist/modules/ekv.js.map +1 -0
  107. package/dist/modules/ens.d.ts +122 -0
  108. package/dist/modules/ens.d.ts.map +1 -0
  109. package/dist/modules/ens.js +167 -0
  110. package/dist/modules/ens.js.map +1 -0
  111. package/dist/modules/eqs.d.ts +283 -0
  112. package/dist/modules/eqs.d.ts.map +1 -0
  113. package/dist/modules/eqs.js +355 -0
  114. package/dist/modules/eqs.js.map +1 -0
  115. package/dist/modules/esm.d.ts +358 -0
  116. package/dist/modules/esm.d.ts.map +1 -0
  117. package/dist/modules/esm.js +660 -0
  118. package/dist/modules/esm.js.map +1 -0
  119. package/dist/modules/ess.d.ts +96 -0
  120. package/dist/modules/ess.d.ts.map +1 -0
  121. package/dist/modules/ess.js +110 -0
  122. package/dist/modules/ess.js.map +1 -0
  123. package/dist/url.d.ts +31 -0
  124. package/dist/url.d.ts.map +1 -0
  125. package/dist/url.js +47 -0
  126. package/dist/url.js.map +1 -0
  127. package/package.json +47 -0
@@ -0,0 +1,44 @@
1
+ /** Which request-signing scheme a client uses when it authenticates with an access key. */
2
+ import * as rfc9421 from "./rfc9421.js";
3
+ import * as sigv4 from "./sigv4.js";
4
+ /** What euclid has always spoken, and the default. */
5
+ export const SIGV4 = Object.freeze({
6
+ name: "sigv4",
7
+ sign(req, accessKeyId, secretAccessKey, region, service) {
8
+ sigv4.sign(req, accessKeyId, secretAccessKey, region, service);
9
+ },
10
+ verify(req, lookupSecret) {
11
+ return sigv4.verify(req, lookupSecret);
12
+ },
13
+ signatureHeaderNames() {
14
+ return sigv4.SIGNATURE_HEADER_NAMES;
15
+ },
16
+ });
17
+ /** The standard scheme meant to replace SigV4. */
18
+ export const RFC9421 = Object.freeze({
19
+ name: "rfc9421",
20
+ sign(req, accessKeyId, secretAccessKey) {
21
+ rfc9421.sign(req, accessKeyId, secretAccessKey);
22
+ },
23
+ verify(req, lookupSecret) {
24
+ return rfc9421.verify(req, lookupSecret);
25
+ },
26
+ signatureHeaderNames() {
27
+ return rfc9421.SIGNATURE_HEADER_NAMES;
28
+ },
29
+ });
30
+ /**
31
+ * Which scheme, if either, a received request presents a signature for.
32
+ *
33
+ * A routing decision, not a verification: it says which {@link SigningScheme.verify} to call and
34
+ * nothing about whether that call will succeed. Null means the request presents no signature at
35
+ * all - a bearer-token request, or an unsigned one.
36
+ */
37
+ export function signingSchemeOf(req) {
38
+ if (req.get("signature-input"))
39
+ return RFC9421;
40
+ if (req.get("authorization").startsWith(sigv4.ALGORITHM))
41
+ return SIGV4;
42
+ return null;
43
+ }
44
+ //# sourceMappingURL=scheme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheme.js","sourceRoot":"","sources":["../../src/auth/scheme.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAE3F,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAqCpC,sDAAsD;AACtD,MAAM,CAAC,MAAM,KAAK,GAAkB,MAAM,CAAC,MAAM,CAAgB;IAC/D,IAAI,EAAE,OAAO;IACb,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO;QACrD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,CAAC,GAAG,EAAE,YAAY;QACtB,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACzC,CAAC;IACD,oBAAoB;QAClB,OAAO,KAAK,CAAC,sBAAsB,CAAC;IACtC,CAAC;CACF,CAAC,CAAC;AAEH,kDAAkD;AAClD,MAAM,CAAC,MAAM,OAAO,GAAkB,MAAM,CAAC,MAAM,CAAgB;IACjE,IAAI,EAAE,SAAS;IACf,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe;QACpC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,CAAC,GAAG,EAAE,YAAY;QACtB,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC3C,CAAC;IACD,oBAAoB;QAClB,OAAO,OAAO,CAAC,sBAAsB,CAAC;IACxC,CAAC;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,IAAI,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAAE,OAAO,OAAO,CAAC;IAC/C,IAAI,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACvE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,37 @@
1
+ /** The view of a request that the signing schemes work on. */
2
+ /**
3
+ * A minimal, transport-agnostic request: method, target, headers and body.
4
+ *
5
+ * Deliberately not node's `ClientRequest`. A signature has to be computed over headers that are
6
+ * already set and then written back as more headers, which needs a mutable object that exists
7
+ * before anything is sent - and it has to be the same object the verifier sees on the other side,
8
+ * so that signing and verification are demonstrably the same canonicalisation rather than two
9
+ * implementations of one description.
10
+ *
11
+ * Header names are stored lowercase and values trimmed, because that is what both canonical forms
12
+ * are defined over: HTTP header names are case-insensitive, and neither SigV4 nor RFC 9421 treats
13
+ * the surrounding whitespace of a value as part of it.
14
+ */
15
+ export declare class SignableRequest {
16
+ #private;
17
+ readonly method: string;
18
+ readonly target: string;
19
+ constructor(method: string, target: string);
20
+ get body(): Buffer;
21
+ get scheme(): string;
22
+ /** The headers, keyed by lowercase name, in the order they were first set. */
23
+ get headers(): Record<string, string>;
24
+ /** Sets a header, and returns this so calls can be chained. */
25
+ header(name: string, value: string): this;
26
+ /** Copies every header of an object onto this request. */
27
+ headersFrom(headers: Record<string, string | undefined>): this;
28
+ /** A header's value, or the empty string when the request does not carry it. */
29
+ get(name: string): string;
30
+ /** Whether the request carries a header at all, which is not the same as it being non-empty. */
31
+ has(name: string): boolean;
32
+ /** Sets the body. Text is encoded as UTF-8, which is what both ends hash. */
33
+ setBody(body: Buffer | string | null | undefined): this;
34
+ /** Sets the URI scheme. Ignored when empty, leaving the https default in place. */
35
+ setScheme(scheme: string | null | undefined): this;
36
+ }
37
+ //# sourceMappingURL=signable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signable.d.ts","sourceRoot":"","sources":["../../src/auth/signable.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAQZ,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAK1C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,8EAA8E;IAC9E,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEpC;IAED,+DAA+D;IAC/D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC,0DAA0D;IAC1D,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI;IAO9D,gFAAgF;IAChF,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIzB,gGAAgG;IAChG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,6EAA6E;IAC7E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAKvD,mFAAmF;IACnF,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;CAInD"}
@@ -0,0 +1,70 @@
1
+ /** The view of a request that the signing schemes work on. */
2
+ /**
3
+ * A minimal, transport-agnostic request: method, target, headers and body.
4
+ *
5
+ * Deliberately not node's `ClientRequest`. A signature has to be computed over headers that are
6
+ * already set and then written back as more headers, which needs a mutable object that exists
7
+ * before anything is sent - and it has to be the same object the verifier sees on the other side,
8
+ * so that signing and verification are demonstrably the same canonicalisation rather than two
9
+ * implementations of one description.
10
+ *
11
+ * Header names are stored lowercase and values trimmed, because that is what both canonical forms
12
+ * are defined over: HTTP header names are case-insensitive, and neither SigV4 nor RFC 9421 treats
13
+ * the surrounding whitespace of a value as part of it.
14
+ */
15
+ export class SignableRequest {
16
+ method;
17
+ target;
18
+ #headers = new Map();
19
+ #body = Buffer.alloc(0);
20
+ // https, because that is how euclid is reached anywhere the distinction can matter. A
21
+ // plain-HTTP caller sets it so that both ends agree on whether the port belongs in "@authority".
22
+ #scheme = "https";
23
+ constructor(method, target) {
24
+ this.method = method;
25
+ this.target = target;
26
+ }
27
+ get body() {
28
+ return this.#body;
29
+ }
30
+ get scheme() {
31
+ return this.#scheme;
32
+ }
33
+ /** The headers, keyed by lowercase name, in the order they were first set. */
34
+ get headers() {
35
+ return Object.fromEntries(this.#headers);
36
+ }
37
+ /** Sets a header, and returns this so calls can be chained. */
38
+ header(name, value) {
39
+ this.#headers.set(name.toLowerCase(), value.trim());
40
+ return this;
41
+ }
42
+ /** Copies every header of an object onto this request. */
43
+ headersFrom(headers) {
44
+ for (const [name, value] of Object.entries(headers)) {
45
+ if (value !== undefined)
46
+ this.header(name, value);
47
+ }
48
+ return this;
49
+ }
50
+ /** A header's value, or the empty string when the request does not carry it. */
51
+ get(name) {
52
+ return this.#headers.get(name.toLowerCase()) ?? "";
53
+ }
54
+ /** Whether the request carries a header at all, which is not the same as it being non-empty. */
55
+ has(name) {
56
+ return this.#headers.has(name.toLowerCase());
57
+ }
58
+ /** Sets the body. Text is encoded as UTF-8, which is what both ends hash. */
59
+ setBody(body) {
60
+ this.#body = body == null ? Buffer.alloc(0) : typeof body === "string" ? Buffer.from(body, "utf8") : body;
61
+ return this;
62
+ }
63
+ /** Sets the URI scheme. Ignored when empty, leaving the https default in place. */
64
+ setScheme(scheme) {
65
+ if (scheme)
66
+ this.#scheme = scheme.toLowerCase();
67
+ return this;
68
+ }
69
+ }
70
+ //# sourceMappingURL=signable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signable.js","sourceRoot":"","sources":["../../src/auth/signable.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,eAAe;IACjB,MAAM,CAAS;IACf,MAAM,CAAS;IAExB,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,KAAK,GAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChC,sFAAsF;IACtF,iGAAiG;IACjG,OAAO,GAAG,OAAO,CAAC;IAElB,YAAY,MAAc,EAAE,MAAc;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,8EAA8E;IAC9E,IAAI,OAAO;QACT,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,+DAA+D;IAC/D,MAAM,CAAC,IAAY,EAAE,KAAa;QAChC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0DAA0D;IAC1D,WAAW,CAAC,OAA2C;QACrD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,IAAI,KAAK,KAAK,SAAS;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gFAAgF;IAChF,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACrD,CAAC;IAED,gGAAgG;IAChG,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,6EAA6E;IAC7E,OAAO,CAAC,IAAwC;QAC9C,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1G,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mFAAmF;IACnF,SAAS,CAAC,MAAiC;QACzC,IAAI,MAAM;YAAE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * AWS Signature Version 4 request signing and verification.
3
+ *
4
+ * Ported from euclid's `Core::SigV4` (C++, `core/src/SigV4.cpp`), by way of euclid-pdk. Unlike real
5
+ * AWS, the target service and the action live in `x-euclid-*` headers rather than in the URI, so
6
+ * those headers are always part of the signed set: a fixed list rather than the client-chosen
7
+ * `SignedHeaders` that AWS allows, so that nothing in transit can narrow what a signature actually
8
+ * covers and still have it verify.
9
+ */
10
+ import type { SignableRequest } from "./signable.js";
11
+ export declare const ALGORITHM = "AWS4-HMAC-SHA256";
12
+ /**
13
+ * Signature headers, in the case they are sent in, for callers that copy them onto some other
14
+ * request object afterwards.
15
+ */
16
+ export declare const SIGNATURE_HEADER_NAMES: readonly ["x-amz-date", "x-amz-content-sha256", "Authorization"];
17
+ /** The `<key>/<date>/<region>/<service>/aws4_request` scope out of an Authorization header. */
18
+ export interface CredentialScope {
19
+ accessKeyId: string;
20
+ dateStamp: string;
21
+ region: string;
22
+ service: string;
23
+ }
24
+ /** An Authorization header split into its parts. */
25
+ export interface ParsedAuthorization {
26
+ scope: CredentialScope;
27
+ signedHeaders: string;
28
+ signature: string;
29
+ }
30
+ /** The headers a SigV4 signature always covers, lowercase, in signing order. */
31
+ export declare function signedHeaderNames(): readonly string[];
32
+ /**
33
+ * Parses `AWS4-HMAC-SHA256 Credential=..., SignedHeaders=..., Signature=...`.
34
+ *
35
+ * Answers null when the header is absent or not well-formed, which the caller treats exactly as it
36
+ * treats a signature that does not match - see {@link verify}.
37
+ */
38
+ export declare function parseAuthorizationHeader(headerValue: string | undefined): ParsedAuthorization | null;
39
+ /**
40
+ * Percent-decodes each name and value, re-encodes them per SigV4's rules, and sorts by name.
41
+ *
42
+ * euclid POSTs everything to `/` and carries its arguments in the body, so in practice this
43
+ * canonicalises the empty string. It is here because the canonical request has a slot for it and a
44
+ * signature computed with a different filling for that slot does not verify.
45
+ */
46
+ export declare function canonicalizeQueryString(rawQuery: string): string;
47
+ /** Builds the SigV4 canonical request string. */
48
+ export declare function buildCanonicalRequest(method: string, canonicalUri: string, canonicalQuery: string, headers: Record<string, string>, headerNames: readonly string[], payloadHashHex: string): string;
49
+ /** Builds the SigV4 string-to-sign. */
50
+ export declare function buildStringToSign(amzDate: string, credentialScope: string, canonicalRequestHashHex: string): string;
51
+ /** Derives the signing key via the kDate -> kRegion -> kService -> kSigning HMAC chain. */
52
+ export declare function deriveSigningKey(secretAccessKey: string, dateStamp: string, region: string, service: string): Buffer;
53
+ /**
54
+ * Signs a request in place: sets x-amz-date, x-amz-content-sha256 and Authorization.
55
+ *
56
+ * Call it once every other header the signature covers - the `x-euclid-*` ones and host - and the
57
+ * body are already set on `req`. Anything set afterwards is not covered, and on the server that is
58
+ * indistinguishable from an attacker having added it.
59
+ */
60
+ export declare function sign(req: SignableRequest, accessKeyId: string, secretAccessKey: string, region: string, service: string): void;
61
+ /**
62
+ * Verifies a SigV4-signed request, answering the access key ID it was signed with.
63
+ *
64
+ * Recomputes the signature from the request exactly as received and compares it in constant time,
65
+ * so any change to a signed header or to the body between signing and here makes this fail.
66
+ *
67
+ * Answers null on every failure - missing or malformed header, unknown key, stale timestamp,
68
+ * mismatched signature - without saying which, the way token verification collapses its failure
69
+ * modes into one rejection. A caller that could tell them apart would be an oracle.
70
+ */
71
+ export declare function verify(req: SignableRequest, lookupSecret: (accessKeyId: string) => string | null | undefined, maxSkewMs?: number): string | null;
72
+ //# sourceMappingURL=sigv4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigv4.d.ts","sourceRoot":"","sources":["../../src/auth/sigv4.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,eAAO,MAAM,SAAS,qBAAqB,CAAC;AAsB5C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,kEAAmE,CAAC;AAEvG,+FAA+F;AAC/F,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,eAAe,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,GAAG,IAAI,CAsBpG;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAchE;AAED,iDAAiD;AACjD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,cAAc,EAAE,MAAM,GACrB,MAAM,CAGR;AAED,uCAAuC;AACvC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,GAAG,MAAM,CAEnH;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKpH;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAClB,GAAG,EAAE,eAAe,EACpB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,IAAI,CA0BN;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CACpB,GAAG,EAAE,eAAe,EACpB,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,EAChE,SAAS,GAAE,MAA4B,GACtC,MAAM,GAAG,IAAI,CAuCf"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * AWS Signature Version 4 request signing and verification.
3
+ *
4
+ * Ported from euclid's `Core::SigV4` (C++, `core/src/SigV4.cpp`), by way of euclid-pdk. Unlike real
5
+ * AWS, the target service and the action live in `x-euclid-*` headers rather than in the URI, so
6
+ * those headers are always part of the signed set: a fixed list rather than the client-chosen
7
+ * `SignedHeaders` that AWS allows, so that nothing in transit can narrow what a signature actually
8
+ * covers and still have it verify.
9
+ */
10
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
11
+ export const ALGORITHM = "AWS4-HMAC-SHA256";
12
+ const SCOPE_TERMINATOR = "aws4_request";
13
+ const DEFAULT_MAX_SKEW_MS = 15 * 60 * 1000;
14
+ /**
15
+ * Always part of the signature, in the (already alphabetical) order the canonical request needs.
16
+ * host and the two x-amz-* headers give the usual SigV4 transport and payload integrity; the
17
+ * x-euclid-* headers are in there because that is where euclid carries the routing information AWS
18
+ * would put in the URI, and a signature that left them out would authenticate a request without
19
+ * authenticating what it asks for.
20
+ */
21
+ const SIGNED_HEADER_NAMES = [
22
+ "host",
23
+ "x-amz-content-sha256",
24
+ "x-amz-date",
25
+ "x-euclid-account-id",
26
+ "x-euclid-action",
27
+ "x-euclid-region",
28
+ "x-euclid-target",
29
+ "x-euclid-user-id",
30
+ ];
31
+ /**
32
+ * Signature headers, in the case they are sent in, for callers that copy them onto some other
33
+ * request object afterwards.
34
+ */
35
+ export const SIGNATURE_HEADER_NAMES = ["x-amz-date", "x-amz-content-sha256", "Authorization"];
36
+ /** The headers a SigV4 signature always covers, lowercase, in signing order. */
37
+ export function signedHeaderNames() {
38
+ return SIGNED_HEADER_NAMES;
39
+ }
40
+ /**
41
+ * Parses `AWS4-HMAC-SHA256 Credential=..., SignedHeaders=..., Signature=...`.
42
+ *
43
+ * Answers null when the header is absent or not well-formed, which the caller treats exactly as it
44
+ * treats a signature that does not match - see {@link verify}.
45
+ */
46
+ export function parseAuthorizationHeader(headerValue) {
47
+ if (!headerValue || !headerValue.startsWith(ALGORITHM))
48
+ return null;
49
+ let credential = "";
50
+ let signedHeaders = "";
51
+ let signature = "";
52
+ for (const part of headerValue.slice(ALGORITHM.length).trim().split(",")) {
53
+ const trimmed = part.trim();
54
+ if (trimmed.startsWith("Credential="))
55
+ credential = trimmed.slice("Credential=".length);
56
+ else if (trimmed.startsWith("SignedHeaders="))
57
+ signedHeaders = trimmed.slice("SignedHeaders=".length);
58
+ else if (trimmed.startsWith("Signature="))
59
+ signature = trimmed.slice("Signature=".length);
60
+ }
61
+ if (!credential || !signedHeaders || !signature)
62
+ return null;
63
+ const parts = credential.split("/");
64
+ if (parts.length !== 5 || parts[4] !== SCOPE_TERMINATOR)
65
+ return null;
66
+ return {
67
+ scope: { accessKeyId: parts[0], dateStamp: parts[1], region: parts[2], service: parts[3] },
68
+ signedHeaders,
69
+ signature,
70
+ };
71
+ }
72
+ /**
73
+ * Percent-decodes each name and value, re-encodes them per SigV4's rules, and sorts by name.
74
+ *
75
+ * euclid POSTs everything to `/` and carries its arguments in the body, so in practice this
76
+ * canonicalises the empty string. It is here because the canonical request has a slot for it and a
77
+ * signature computed with a different filling for that slot does not verify.
78
+ */
79
+ export function canonicalizeQueryString(rawQuery) {
80
+ if (!rawQuery)
81
+ return "";
82
+ const params = [];
83
+ for (const pair of rawQuery.split("&")) {
84
+ if (!pair)
85
+ continue;
86
+ const equals = pair.indexOf("=");
87
+ const name = equals < 0 ? pair : pair.slice(0, equals);
88
+ const value = equals < 0 ? "" : pair.slice(equals + 1);
89
+ params.push([uriEncode(percentDecode(name)), uriEncode(percentDecode(value))]);
90
+ }
91
+ params.sort((left, right) => (left[0] < right[0] ? -1 : left[0] > right[0] ? 1 : left[1] < right[1] ? -1 : left[1] > right[1] ? 1 : 0));
92
+ return params.map(([name, value]) => `${name}=${value}`).join("&");
93
+ }
94
+ /** Builds the SigV4 canonical request string. */
95
+ export function buildCanonicalRequest(method, canonicalUri, canonicalQuery, headers, headerNames, payloadHashHex) {
96
+ const canonicalHeaders = headerNames.map((name) => `${name}:${headers[name] ?? ""}\n`).join("");
97
+ return [method, canonicalUri, canonicalQuery, canonicalHeaders, headerNames.join(";"), payloadHashHex].join("\n");
98
+ }
99
+ /** Builds the SigV4 string-to-sign. */
100
+ export function buildStringToSign(amzDate, credentialScope, canonicalRequestHashHex) {
101
+ return [ALGORITHM, amzDate, credentialScope, canonicalRequestHashHex].join("\n");
102
+ }
103
+ /** Derives the signing key via the kDate -> kRegion -> kService -> kSigning HMAC chain. */
104
+ export function deriveSigningKey(secretAccessKey, dateStamp, region, service) {
105
+ const kDate = hmac(Buffer.from(`AWS4${secretAccessKey}`, "utf8"), dateStamp);
106
+ const kRegion = hmac(kDate, region);
107
+ const kService = hmac(kRegion, service);
108
+ return hmac(kService, SCOPE_TERMINATOR);
109
+ }
110
+ /**
111
+ * Signs a request in place: sets x-amz-date, x-amz-content-sha256 and Authorization.
112
+ *
113
+ * Call it once every other header the signature covers - the `x-euclid-*` ones and host - and the
114
+ * body are already set on `req`. Anything set afterwards is not covered, and on the server that is
115
+ * indistinguishable from an attacker having added it.
116
+ */
117
+ export function sign(req, accessKeyId, secretAccessKey, region, service) {
118
+ const amzDate = formatAmzDate(new Date());
119
+ const dateStamp = amzDate.slice(0, 8);
120
+ req.header("x-amz-date", amzDate);
121
+ req.header("x-amz-content-sha256", sha256Hex(req.body));
122
+ const [canonicalUri, canonicalQuery] = splitTarget(req.target);
123
+ const canonicalRequest = buildCanonicalRequest(req.method, canonicalUri, canonicalQuery, req.headers, SIGNED_HEADER_NAMES, req.get("x-amz-content-sha256"));
124
+ const credentialScope = `${dateStamp}/${region}/${service}/${SCOPE_TERMINATOR}`;
125
+ const stringToSign = buildStringToSign(amzDate, credentialScope, sha256Hex(Buffer.from(canonicalRequest, "utf8")));
126
+ const signature = hmac(deriveSigningKey(secretAccessKey, dateStamp, region, service), stringToSign).toString("hex");
127
+ req.header("Authorization", `${ALGORITHM} Credential=${accessKeyId}/${credentialScope}, ` +
128
+ `SignedHeaders=${SIGNED_HEADER_NAMES.join(";")}, Signature=${signature}`);
129
+ }
130
+ /**
131
+ * Verifies a SigV4-signed request, answering the access key ID it was signed with.
132
+ *
133
+ * Recomputes the signature from the request exactly as received and compares it in constant time,
134
+ * so any change to a signed header or to the body between signing and here makes this fail.
135
+ *
136
+ * Answers null on every failure - missing or malformed header, unknown key, stale timestamp,
137
+ * mismatched signature - without saying which, the way token verification collapses its failure
138
+ * modes into one rejection. A caller that could tell them apart would be an oracle.
139
+ */
140
+ export function verify(req, lookupSecret, maxSkewMs = DEFAULT_MAX_SKEW_MS) {
141
+ const parsed = parseAuthorizationHeader(req.get("authorization"));
142
+ if (parsed === null)
143
+ return null;
144
+ // Fixed policy rather than client-negotiated: a request does not get to choose how little of
145
+ // itself it authenticates.
146
+ if (parsed.signedHeaders !== SIGNED_HEADER_NAMES.join(";"))
147
+ return null;
148
+ const secret = lookupSecret(parsed.scope.accessKeyId);
149
+ if (secret == null)
150
+ return null;
151
+ const headers = req.headers;
152
+ const amzDate = headers["x-amz-date"] ?? "";
153
+ if (amzDate.length < 8 || amzDate.slice(0, 8) !== parsed.scope.dateStamp)
154
+ return null;
155
+ const requestTime = parseAmzDate(amzDate);
156
+ if (requestTime === null || Math.abs(Date.now() - requestTime) > maxSkewMs)
157
+ return null;
158
+ const payloadHash = headers["x-amz-content-sha256"];
159
+ if (payloadHash === undefined || payloadHash !== sha256Hex(req.body))
160
+ return null;
161
+ const [canonicalUri, canonicalQuery] = splitTarget(req.target);
162
+ const canonicalRequest = buildCanonicalRequest(req.method, canonicalUri, canonicalQuery, headers, SIGNED_HEADER_NAMES, payloadHash);
163
+ const credentialScope = `${parsed.scope.dateStamp}/${parsed.scope.region}/${parsed.scope.service}/${SCOPE_TERMINATOR}`;
164
+ const stringToSign = buildStringToSign(amzDate, credentialScope, sha256Hex(Buffer.from(canonicalRequest, "utf8")));
165
+ const expected = hmac(deriveSigningKey(secret, parsed.scope.dateStamp, parsed.scope.region, parsed.scope.service), stringToSign).toString("hex");
166
+ return equal(expected, parsed.signature) ? parsed.scope.accessKeyId : null;
167
+ }
168
+ // -- internals -------------------------------------------------------------------------------
169
+ /** `20150830T123600Z`, which is what SigV4 dates look like. */
170
+ function formatAmzDate(when) {
171
+ return when.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}/, "");
172
+ }
173
+ function parseAmzDate(amzDate) {
174
+ const match = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(amzDate);
175
+ if (!match)
176
+ return null;
177
+ const [, year, month, day, hour, minute, second] = match.map(Number);
178
+ return Date.UTC(year, month - 1, day, hour, minute, second);
179
+ }
180
+ function splitTarget(target) {
181
+ const question = target.indexOf("?");
182
+ if (question < 0)
183
+ return [target, ""];
184
+ return [target.slice(0, question), canonicalizeQueryString(target.slice(question + 1))];
185
+ }
186
+ /** SigV4's URI-encoding: everything but the unreserved set, uppercase hex, byte by byte. */
187
+ function uriEncode(value) {
188
+ let out = "";
189
+ for (const byte of value) {
190
+ const char = String.fromCharCode(byte);
191
+ if (/[A-Za-z0-9\-_.~]/.test(char))
192
+ out += char;
193
+ else
194
+ out += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
195
+ }
196
+ return out;
197
+ }
198
+ function percentDecode(value) {
199
+ const out = [];
200
+ let i = 0;
201
+ while (i < value.length) {
202
+ if (value[i] === "%" && i + 2 < value.length) {
203
+ const hex = value.slice(i + 1, i + 3);
204
+ if (/^[0-9A-Fa-f]{2}$/.test(hex)) {
205
+ out.push(parseInt(hex, 16));
206
+ i += 3;
207
+ continue;
208
+ }
209
+ }
210
+ out.push(...Buffer.from(value[i], "utf8"));
211
+ i += 1;
212
+ }
213
+ return Buffer.from(out);
214
+ }
215
+ function sha256Hex(data) {
216
+ return createHash("sha256").update(data).digest("hex");
217
+ }
218
+ function hmac(key, data) {
219
+ return createHmac("sha256", key).update(data, "utf8").digest();
220
+ }
221
+ /** Constant-time string comparison, which is what a signature check has to be. */
222
+ function equal(left, right) {
223
+ const a = Buffer.from(left, "utf8");
224
+ const b = Buffer.from(right, "utf8");
225
+ return a.length === b.length && timingSafeEqual(a, b);
226
+ }
227
+ //# sourceMappingURL=sigv4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigv4.js","sourceRoot":"","sources":["../../src/auth/sigv4.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAItE,MAAM,CAAC,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAC5C,MAAM,gBAAgB,GAAG,cAAc,CAAC;AACxC,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG;IAC1B,MAAM;IACN,sBAAsB;IACtB,YAAY;IACZ,qBAAqB;IACrB,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;CACV,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,YAAY,EAAE,sBAAsB,EAAE,eAAe,CAAU,CAAC;AAiBvG,gFAAgF;AAChF,MAAM,UAAU,iBAAiB;IAC/B,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAA+B;IACtE,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpE,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,aAAa,GAAG,EAAE,CAAC;IACvB,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACzE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC;YAAE,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;aACnF,IAAI,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC;YAAE,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;aACjG,IAAI,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAC5F,CAAC;IACD,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE7D,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAErE,OAAO;QACL,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE;QAC9F,aAAa;QACb,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEzB,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxI,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrE,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,qBAAqB,CACnC,MAAc,EACd,YAAoB,EACpB,cAAsB,EACtB,OAA+B,EAC/B,WAA8B,EAC9B,cAAsB;IAEtB,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChG,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpH,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,eAAuB,EAAE,uBAA+B;IACzG,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,uBAAuB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,gBAAgB,CAAC,eAAuB,EAAE,SAAiB,EAAE,MAAc,EAAE,OAAe;IAC1G,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,eAAe,EAAE,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxC,OAAO,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAClB,GAAoB,EACpB,WAAmB,EACnB,eAAuB,EACvB,MAAc,EACd,OAAe;IAEf,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtC,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAClC,GAAG,CAAC,MAAM,CAAC,sBAAsB,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAExD,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,gBAAgB,GAAG,qBAAqB,CAC5C,GAAG,CAAC,MAAM,EACV,YAAY,EACZ,cAAc,EACd,GAAG,CAAC,OAAO,EACX,mBAAmB,EACnB,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAChC,CAAC;IAEF,MAAM,eAAe,GAAG,GAAG,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAChF,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACnH,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpH,GAAG,CAAC,MAAM,CACR,eAAe,EACf,GAAG,SAAS,eAAe,WAAW,IAAI,eAAe,IAAI;QAC3D,iBAAiB,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,SAAS,EAAE,CAC3E,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,MAAM,CACpB,GAAoB,EACpB,YAAgE,EAChE,YAAoB,mBAAmB;IAEvC,MAAM,MAAM,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;IAClE,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjC,6FAA6F;IAC7F,2BAA2B;IAC3B,IAAI,MAAM,CAAC,aAAa,KAAK,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExE,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACtD,IAAI,MAAM,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAEhC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC5B,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAEtF,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,GAAG,SAAS;QAAE,OAAO,IAAI,CAAC;IAExF,MAAM,WAAW,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACpD,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAElF,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,gBAAgB,GAAG,qBAAqB,CAC5C,GAAG,CAAC,MAAM,EACV,YAAY,EACZ,cAAc,EACd,OAAO,EACP,mBAAmB,EACnB,WAAW,CACZ,CAAC;IAEF,MAAM,eAAe,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC;IACvH,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACnH,MAAM,QAAQ,GAAG,IAAI,CACnB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAC3F,YAAY,CACb,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElB,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E,CAAC;AAED,+FAA+F;AAE/F,+DAA+D;AAC/D,SAAS,aAAa,CAAC,IAAU;IAC/B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,KAAK,GAAG,gDAAgD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7E,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAA6D,CAAC;IACjI,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,uBAAuB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED,4FAA4F;AAC5F,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,GAAG,IAAI,IAAI,CAAC;;YAC1C,GAAG,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC5B,CAAC,IAAI,CAAC,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5C,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,IAAI,CAAC,GAAW,EAAE,IAAY;IACrC,OAAO,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;AACjE,CAAC;AAED,kFAAkF;AAClF,SAAS,KAAK,CAAC,IAAY,EAAE,KAAa;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The `~/.euclid/credentials` file, shared with euclid-cli, euclid-jdk and euclid-pdk.
3
+ *
4
+ * All four clients read and write the same file, so a login from any of them is picked up by the
5
+ * others. That makes the field names a wire format rather than an implementation detail: the
6
+ * namespace key is `namespace` (not `nameSpace`), `isAdmin` travels alongside the token, and an
7
+ * absent namespace is written as an empty string rather than null so the CLI's string reader can
8
+ * take it. `baseUrl` is the one field the CLI has no equivalent for - it is what lets a cached
9
+ * session be recognised as belonging to the server being talked to now.
10
+ */
11
+ /** One cached login. */
12
+ export interface CachedCredentials {
13
+ token: string;
14
+ userId: string;
15
+ accountId: string;
16
+ region: string;
17
+ accessKeyId: string;
18
+ secretAccessKey: string;
19
+ isAdmin: boolean;
20
+ baseUrl: string;
21
+ namespace: string;
22
+ /** The document as it was read, for fields a later euclid added that this one does not name. */
23
+ raw: Record<string, unknown>;
24
+ }
25
+ /**
26
+ * Where the credentials live.
27
+ *
28
+ * Resolved per call rather than captured at import, mirroring euclid-cli's
29
+ * `Credentials::FilePath()`: the home directory is read when the file is actually touched, so a
30
+ * process that changes it is not left talking to a stale path. `EUCLID_CREDENTIALS_FILE` overrides
31
+ * it, which is also how a euclid-managed application is handed its own credentials.
32
+ */
33
+ export declare function credentialsPath(): string;
34
+ /** The cached credentials, or null when there is no readable, well-formed file. */
35
+ export declare function load(): Promise<CachedCredentials | null>;
36
+ /** Writes the credentials, readable by their owner alone. */
37
+ export declare function save(credentials: CachedCredentials): Promise<void>;
38
+ /**
39
+ * Patches the cached namespace in place, if what is cached belongs to `baseUrl`.
40
+ *
41
+ * Keeps the file in step when a session's namespace changes outside of a login. A no-op when
42
+ * nothing is cached for that server, in keeping with the best-effort nature of the cache: failing
43
+ * to record a namespace is not a reason to fail the call that changed it.
44
+ */
45
+ export declare function updateNamespace(baseUrl: string, namespace: string): Promise<void>;
46
+ /**
47
+ * Whether a JWT is well-formed and its `exp` is still in the future.
48
+ *
49
+ * Checked locally to avoid a round trip that would only tell us what the token already says. The
50
+ * signature is not verified - the client does not hold the server's secret, and a token the client
51
+ * forged for itself would be rejected on arrival anyway.
52
+ */
53
+ export declare function isTokenValid(token: string): boolean;
54
+ /** An empty set of credentials, which is what every field defaults from. */
55
+ export declare function emptyCredentials(): CachedCredentials;
56
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,wBAAwB;AACxB,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,mFAAmF;AACnF,wBAAsB,IAAI,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAW9D;AAED,6DAA6D;AAC7D,wBAAsB,IAAI,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAYnD;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,IAAI,iBAAiB,CAapD"}