@c9up/transit 0.1.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/dist/Oauth1Driver.d.ts +68 -0
  4. package/dist/Oauth1Driver.d.ts.map +1 -0
  5. package/dist/Oauth1Driver.js +148 -0
  6. package/dist/Oauth1Driver.js.map +1 -0
  7. package/dist/Oauth2Driver.d.ts +89 -0
  8. package/dist/Oauth2Driver.d.ts.map +1 -0
  9. package/dist/Oauth2Driver.js +196 -0
  10. package/dist/Oauth2Driver.js.map +1 -0
  11. package/dist/TransitManager.d.ts +59 -0
  12. package/dist/TransitManager.d.ts.map +1 -0
  13. package/dist/TransitManager.js +100 -0
  14. package/dist/TransitManager.js.map +1 -0
  15. package/dist/TransitProvider.d.ts +26 -0
  16. package/dist/TransitProvider.d.ts.map +1 -0
  17. package/dist/TransitProvider.js +32 -0
  18. package/dist/TransitProvider.js.map +1 -0
  19. package/dist/apple.d.ts +45 -0
  20. package/dist/apple.d.ts.map +1 -0
  21. package/dist/apple.js +80 -0
  22. package/dist/apple.js.map +1 -0
  23. package/dist/ber.d.ts +50 -0
  24. package/dist/ber.d.ts.map +1 -0
  25. package/dist/ber.js +156 -0
  26. package/dist/ber.js.map +1 -0
  27. package/dist/c14n.d.ts +38 -0
  28. package/dist/c14n.d.ts.map +1 -0
  29. package/dist/c14n.js +129 -0
  30. package/dist/c14n.js.map +1 -0
  31. package/dist/config.d.ts +115 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +146 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/configure.d.ts +18 -0
  36. package/dist/configure.d.ts.map +1 -0
  37. package/dist/configure.js +33 -0
  38. package/dist/configure.js.map +1 -0
  39. package/dist/drivers/AppleDriver.d.ts +36 -0
  40. package/dist/drivers/AppleDriver.d.ts.map +1 -0
  41. package/dist/drivers/AppleDriver.js +58 -0
  42. package/dist/drivers/AppleDriver.js.map +1 -0
  43. package/dist/drivers/DiscordDriver.d.ts +15 -0
  44. package/dist/drivers/DiscordDriver.d.ts.map +1 -0
  45. package/dist/drivers/DiscordDriver.js +45 -0
  46. package/dist/drivers/DiscordDriver.js.map +1 -0
  47. package/dist/drivers/FacebookDriver.d.ts +15 -0
  48. package/dist/drivers/FacebookDriver.d.ts.map +1 -0
  49. package/dist/drivers/FacebookDriver.js +47 -0
  50. package/dist/drivers/FacebookDriver.js.map +1 -0
  51. package/dist/drivers/GitHubDriver.d.ts +33 -0
  52. package/dist/drivers/GitHubDriver.d.ts.map +1 -0
  53. package/dist/drivers/GitHubDriver.js +72 -0
  54. package/dist/drivers/GitHubDriver.js.map +1 -0
  55. package/dist/drivers/GoogleDriver.d.ts +16 -0
  56. package/dist/drivers/GoogleDriver.d.ts.map +1 -0
  57. package/dist/drivers/GoogleDriver.js +31 -0
  58. package/dist/drivers/GoogleDriver.js.map +1 -0
  59. package/dist/drivers/LdapDirectory.d.ts +51 -0
  60. package/dist/drivers/LdapDirectory.d.ts.map +1 -0
  61. package/dist/drivers/LdapDirectory.js +127 -0
  62. package/dist/drivers/LdapDirectory.js.map +1 -0
  63. package/dist/drivers/LinkedInDriver.d.ts +29 -0
  64. package/dist/drivers/LinkedInDriver.d.ts.map +1 -0
  65. package/dist/drivers/LinkedInDriver.js +97 -0
  66. package/dist/drivers/LinkedInDriver.js.map +1 -0
  67. package/dist/drivers/LinkedInOpenidConnectDriver.d.ts +17 -0
  68. package/dist/drivers/LinkedInOpenidConnectDriver.d.ts.map +1 -0
  69. package/dist/drivers/LinkedInOpenidConnectDriver.js +27 -0
  70. package/dist/drivers/LinkedInOpenidConnectDriver.js.map +1 -0
  71. package/dist/drivers/OidcDriver.d.ts +64 -0
  72. package/dist/drivers/OidcDriver.d.ts.map +1 -0
  73. package/dist/drivers/OidcDriver.js +259 -0
  74. package/dist/drivers/OidcDriver.js.map +1 -0
  75. package/dist/drivers/SamlDriver.d.ts +66 -0
  76. package/dist/drivers/SamlDriver.d.ts.map +1 -0
  77. package/dist/drivers/SamlDriver.js +228 -0
  78. package/dist/drivers/SamlDriver.js.map +1 -0
  79. package/dist/drivers/SpotifyDriver.d.ts +16 -0
  80. package/dist/drivers/SpotifyDriver.d.ts.map +1 -0
  81. package/dist/drivers/SpotifyDriver.js +34 -0
  82. package/dist/drivers/SpotifyDriver.js.map +1 -0
  83. package/dist/drivers/TwitterDriver.d.ts +21 -0
  84. package/dist/drivers/TwitterDriver.d.ts.map +1 -0
  85. package/dist/drivers/TwitterDriver.js +46 -0
  86. package/dist/drivers/TwitterDriver.js.map +1 -0
  87. package/dist/drivers/TwitterXDriver.d.ts +22 -0
  88. package/dist/drivers/TwitterXDriver.d.ts.map +1 -0
  89. package/dist/drivers/TwitterXDriver.js +47 -0
  90. package/dist/drivers/TwitterXDriver.js.map +1 -0
  91. package/dist/dsig.d.ts +51 -0
  92. package/dist/dsig.d.ts.map +1 -0
  93. package/dist/dsig.js +273 -0
  94. package/dist/dsig.js.map +1 -0
  95. package/dist/index.d.ts +38 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +33 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/jwt.d.ts +135 -0
  100. package/dist/jwt.d.ts.map +1 -0
  101. package/dist/jwt.js +167 -0
  102. package/dist/jwt.js.map +1 -0
  103. package/dist/ldap.d.ts +82 -0
  104. package/dist/ldap.d.ts.map +1 -0
  105. package/dist/ldap.js +271 -0
  106. package/dist/ldap.js.map +1 -0
  107. package/dist/nodeEnv.d.ts +17 -0
  108. package/dist/nodeEnv.d.ts.map +1 -0
  109. package/dist/nodeEnv.js +33 -0
  110. package/dist/nodeEnv.js.map +1 -0
  111. package/dist/oauth1.d.ts +68 -0
  112. package/dist/oauth1.d.ts.map +1 -0
  113. package/dist/oauth1.js +106 -0
  114. package/dist/oauth1.js.map +1 -0
  115. package/dist/oidc.d.ts +61 -0
  116. package/dist/oidc.d.ts.map +1 -0
  117. package/dist/oidc.js +151 -0
  118. package/dist/oidc.js.map +1 -0
  119. package/dist/quasar.d.ts +14 -0
  120. package/dist/quasar.d.ts.map +1 -0
  121. package/dist/quasar.js +42 -0
  122. package/dist/quasar.js.map +1 -0
  123. package/dist/replay.d.ts +70 -0
  124. package/dist/replay.d.ts.map +1 -0
  125. package/dist/replay.js +82 -0
  126. package/dist/replay.js.map +1 -0
  127. package/dist/saml.d.ts +68 -0
  128. package/dist/saml.d.ts.map +1 -0
  129. package/dist/saml.js +181 -0
  130. package/dist/saml.js.map +1 -0
  131. package/dist/services/main.d.ts +22 -0
  132. package/dist/services/main.d.ts.map +1 -0
  133. package/dist/services/main.js +39 -0
  134. package/dist/services/main.js.map +1 -0
  135. package/dist/testing/FakeTransit.d.ts +82 -0
  136. package/dist/testing/FakeTransit.d.ts.map +1 -0
  137. package/dist/testing/FakeTransit.js +160 -0
  138. package/dist/testing/FakeTransit.js.map +1 -0
  139. package/dist/types.d.ts +118 -0
  140. package/dist/types.d.ts.map +1 -0
  141. package/dist/types.js +27 -0
  142. package/dist/types.js.map +1 -0
  143. package/dist/xml.d.ts +72 -0
  144. package/dist/xml.d.ts.map +1 -0
  145. package/dist/xml.js +353 -0
  146. package/dist/xml.js.map +1 -0
  147. package/package.json +73 -0
  148. package/src/Oauth1Driver.ts +216 -0
  149. package/src/Oauth2Driver.ts +271 -0
  150. package/src/TransitManager.ts +145 -0
  151. package/src/TransitProvider.ts +51 -0
  152. package/src/apple.ts +101 -0
  153. package/src/ber.ts +175 -0
  154. package/src/c14n.ts +187 -0
  155. package/src/config.ts +160 -0
  156. package/src/configure.ts +47 -0
  157. package/src/drivers/AppleDriver.ts +69 -0
  158. package/src/drivers/DiscordDriver.ts +50 -0
  159. package/src/drivers/FacebookDriver.ts +53 -0
  160. package/src/drivers/GitHubDriver.ts +91 -0
  161. package/src/drivers/GoogleDriver.ts +38 -0
  162. package/src/drivers/LdapDirectory.ts +185 -0
  163. package/src/drivers/LinkedInDriver.ts +105 -0
  164. package/src/drivers/LinkedInOpenidConnectDriver.ts +33 -0
  165. package/src/drivers/OidcDriver.ts +379 -0
  166. package/src/drivers/SamlDriver.ts +326 -0
  167. package/src/drivers/SpotifyDriver.ts +38 -0
  168. package/src/drivers/TwitterDriver.ts +55 -0
  169. package/src/drivers/TwitterXDriver.ts +53 -0
  170. package/src/dsig.ts +405 -0
  171. package/src/index.ts +85 -0
  172. package/src/jwt.ts +263 -0
  173. package/src/ldap.ts +374 -0
  174. package/src/nodeEnv.ts +31 -0
  175. package/src/oauth1.ts +144 -0
  176. package/src/oidc.ts +208 -0
  177. package/src/quasar.ts +64 -0
  178. package/src/replay.ts +136 -0
  179. package/src/saml.ts +309 -0
  180. package/src/services/main.ts +47 -0
  181. package/src/testing/FakeTransit.ts +233 -0
  182. package/src/types.ts +150 -0
  183. package/src/xml.ts +438 -0
package/dist/ber.js ADDED
@@ -0,0 +1,156 @@
1
+ /**
2
+ * The encoding LDAP speaks: BER, the subset of it LDAP actually uses.
3
+ *
4
+ * This exists so that nothing an application passes ever becomes part of a
5
+ * string that a server then parses. A search filter here is a structure, not
6
+ * text — its values are written as length-prefixed octets, so a username
7
+ * containing `)(uid=*` is a username containing those characters and cannot
8
+ * become syntax. LDAP injection is not escaped away here; it is unrepresentable.
9
+ */
10
+ /** Universal tags, and the two LDAP builds everything else from. */
11
+ export const BOOLEAN = 0x01;
12
+ export const INTEGER = 0x02;
13
+ export const OCTET_STRING = 0x04;
14
+ export const ENUMERATED = 0x0a;
15
+ export const SEQUENCE = 0x30;
16
+ /** `[APPLICATION n]`, constructed. */
17
+ export const application = (n) => 0x60 | n;
18
+ /** `[APPLICATION n]`, primitive — which a couple of LDAP operations are. */
19
+ export const applicationPrimitive = (n) => 0x40 | n;
20
+ /** `[n]` context-specific, constructed. */
21
+ export const context = (n) => 0xa0 | n;
22
+ /** `[n]` context-specific, primitive. */
23
+ export const contextPrimitive = (n) => 0x80 | n;
24
+ export class BerError extends Error {
25
+ constructor(message) {
26
+ super(`[transit] ${message}`);
27
+ this.name = "BerError";
28
+ }
29
+ }
30
+ /** One tag-length-value element. */
31
+ export function encode(tag, value) {
32
+ return Buffer.concat([Buffer.from([tag]), encodeLength(value.length), value]);
33
+ }
34
+ export function encodeInteger(value, tag = INTEGER) {
35
+ if (!Number.isSafeInteger(value)) {
36
+ throw new BerError(`cannot encode ${value} as an integer`);
37
+ }
38
+ const bytes = [];
39
+ let remaining = value;
40
+ do {
41
+ bytes.unshift(remaining & 0xff);
42
+ remaining >>= 8;
43
+ } while (remaining !== 0 && remaining !== -1);
44
+ // A leading bit set on a positive number would read as negative.
45
+ if (value >= 0 && bytes[0] & 0x80)
46
+ bytes.unshift(0);
47
+ if (value < 0 && !(bytes[0] & 0x80))
48
+ bytes.unshift(0xff);
49
+ return encode(tag, Buffer.from(bytes));
50
+ }
51
+ export function encodeString(value, tag = OCTET_STRING) {
52
+ // The value is written as length-prefixed bytes, never interpolated. That
53
+ // is what makes injection impossible rather than merely escaped.
54
+ return encode(tag, Buffer.from(value, "utf8"));
55
+ }
56
+ export function encodeBoolean(value, tag = BOOLEAN) {
57
+ return encode(tag, Buffer.from([value ? 0xff : 0x00]));
58
+ }
59
+ export function encodeSequence(parts, tag = SEQUENCE) {
60
+ return encode(tag, Buffer.concat(parts));
61
+ }
62
+ /** Read one element at `offset`. */
63
+ export function decode(buffer, offset = 0) {
64
+ if (offset >= buffer.length) {
65
+ throw new BerError("the message ends where an element was expected");
66
+ }
67
+ const tag = buffer[offset];
68
+ const { length, at } = decodeLength(buffer, offset + 1);
69
+ const end = at + length;
70
+ if (end > buffer.length) {
71
+ throw new BerError(`an element claims ${length} bytes and the message holds ${buffer.length - at}`);
72
+ }
73
+ return { tag, value: buffer.subarray(at, end), end };
74
+ }
75
+ /** Every element inside a constructed one. */
76
+ export function decodeSequence(value) {
77
+ const out = [];
78
+ let offset = 0;
79
+ while (offset < value.length) {
80
+ const element = decode(value, offset);
81
+ out.push(element);
82
+ offset = element.end;
83
+ }
84
+ return out;
85
+ }
86
+ export function decodeInteger(value) {
87
+ if (value.length === 0)
88
+ throw new BerError("an integer has no bytes");
89
+ if (value.length > 6) {
90
+ // Beyond this a result code or message id is not something this reads.
91
+ throw new BerError(`an integer of ${value.length} bytes is out of range`);
92
+ }
93
+ let out = value[0] & 0x80 ? -1 : 0;
94
+ for (const byte of value)
95
+ out = out * 256 + byte;
96
+ return out;
97
+ }
98
+ export function decodeString(value) {
99
+ return value.toString("utf8");
100
+ }
101
+ /**
102
+ * How many bytes a whole message occupies, or `undefined` while it is still
103
+ * arriving. LDAP runs over a stream, so a read can stop anywhere.
104
+ */
105
+ export function messageLength(buffer) {
106
+ if (buffer.length < 2)
107
+ return undefined;
108
+ const first = buffer[1];
109
+ if (first < 0x80)
110
+ return 2 + first;
111
+ const count = first & 0x7f;
112
+ if (count === 0 || count > 4) {
113
+ throw new BerError("a message declares a length this refuses to read");
114
+ }
115
+ if (buffer.length < 2 + count)
116
+ return undefined;
117
+ let length = 0;
118
+ for (let i = 0; i < count; i += 1) {
119
+ length = length * 256 + buffer[2 + i];
120
+ }
121
+ return 2 + count + length;
122
+ }
123
+ function encodeLength(length) {
124
+ if (length < 0x80)
125
+ return Buffer.from([length]);
126
+ const bytes = [];
127
+ let remaining = length;
128
+ while (remaining > 0) {
129
+ bytes.unshift(remaining & 0xff);
130
+ remaining = Math.floor(remaining / 256);
131
+ }
132
+ return Buffer.from([0x80 | bytes.length, ...bytes]);
133
+ }
134
+ function decodeLength(buffer, offset) {
135
+ if (offset >= buffer.length) {
136
+ throw new BerError("an element has no length");
137
+ }
138
+ const first = buffer[offset];
139
+ if (first < 0x80)
140
+ return { length: first, at: offset + 1 };
141
+ const count = first & 0x7f;
142
+ if (count === 0) {
143
+ // Indefinite length is legal BER and not legal LDAP; accepting it would
144
+ // mean scanning for a terminator supplied by the other side.
145
+ throw new BerError("an element uses an indefinite length, which LDAP does not");
146
+ }
147
+ if (count > 4 || offset + 1 + count > buffer.length) {
148
+ throw new BerError("an element declares a length this refuses to read");
149
+ }
150
+ let length = 0;
151
+ for (let i = 0; i < count; i += 1) {
152
+ length = length * 256 + buffer[offset + 1 + i];
153
+ }
154
+ return { length, at: offset + 1 + count };
155
+ }
156
+ //# sourceMappingURL=ber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ber.js","sourceRoot":"","sources":["../src/ber.ts"],"names":[],"mappings":"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"}
package/dist/c14n.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Exclusive XML Canonicalization (`xml-exc-c14n#`).
3
+ *
4
+ * A signature is over BYTES, and two parties only agree on which bytes if they
5
+ * agree on this algorithm exactly. Every rule below comes from the
6
+ * specification, and the awkward ones are the ones that matter:
7
+ *
8
+ * - Only namespaces an element **visibly utilizes** are written out, and only
9
+ * when an output ancestor has not already written the same prefix with the
10
+ * same value. That is what makes a signed fragment survive being moved
11
+ * between documents — and it is the whole reason exclusive exists.
12
+ * - An unprefixed attribute is in NO namespace, so it never makes the default
13
+ * namespace visibly utilized.
14
+ * - The `xml` prefix is bound by the XML specification and is never declared.
15
+ *
16
+ * Getting any of these wrong yields a canonical form that differs from the
17
+ * signer's by a few bytes, and every signature then fails — or, worse, one is
18
+ * accepted over a document that is not the one that was signed.
19
+ */
20
+ import { XML_NS, type XmlElement, type XmlNode } from "./xml.js";
21
+ export interface CanonicalizeOptions {
22
+ /**
23
+ * Prefixes to treat the inclusive way, from a `<InclusiveNamespaces
24
+ * PrefixList="…">` transform parameter.
25
+ */
26
+ inclusivePrefixes?: string[];
27
+ /** Comments are excluded unless the algorithm says otherwise. */
28
+ withComments?: boolean;
29
+ /**
30
+ * Nodes to leave out of the output — what the enveloped-signature transform
31
+ * needs, since an element cannot carry a digest of itself.
32
+ */
33
+ omit?: ReadonlySet<XmlNode>;
34
+ }
35
+ /** The canonical form of an element and everything under it. */
36
+ export declare function canonicalize(element: XmlElement, options?: CanonicalizeOptions): string;
37
+ export { XML_NS };
38
+ //# sourceMappingURL=c14n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c14n.d.ts","sourceRoot":"","sources":["../src/c14n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEN,MAAM,EAEN,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,iEAAiE;IACjE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CAC5B;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAC3B,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,mBAAwB,GAC/B,MAAM,CAIR;AAuID,OAAO,EAAE,MAAM,EAAE,CAAC"}
package/dist/c14n.js ADDED
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Exclusive XML Canonicalization (`xml-exc-c14n#`).
3
+ *
4
+ * A signature is over BYTES, and two parties only agree on which bytes if they
5
+ * agree on this algorithm exactly. Every rule below comes from the
6
+ * specification, and the awkward ones are the ones that matter:
7
+ *
8
+ * - Only namespaces an element **visibly utilizes** are written out, and only
9
+ * when an output ancestor has not already written the same prefix with the
10
+ * same value. That is what makes a signed fragment survive being moved
11
+ * between documents — and it is the whole reason exclusive exists.
12
+ * - An unprefixed attribute is in NO namespace, so it never makes the default
13
+ * namespace visibly utilized.
14
+ * - The `xml` prefix is bound by the XML specification and is never declared.
15
+ *
16
+ * Getting any of these wrong yields a canonical form that differs from the
17
+ * signer's by a few bytes, and every signature then fails — or, worse, one is
18
+ * accepted over a document that is not the one that was signed.
19
+ */
20
+ import { resolvePrefix, XML_NS, } from "./xml.js";
21
+ /** The canonical form of an element and everything under it. */
22
+ export function canonicalize(element, options = {}) {
23
+ const out = [];
24
+ writeElement(element, out, new Map(), options);
25
+ return out.join("");
26
+ }
27
+ /**
28
+ * The prefixes this element makes visible: its own, and those of its
29
+ * attributes. The default namespace counts only when the element itself has no
30
+ * prefix.
31
+ */
32
+ function visiblyUtilized(element, inclusivePrefixes) {
33
+ const used = new Set([element.prefix]);
34
+ for (const attribute of element.attributes) {
35
+ if (attribute.prefix !== "")
36
+ used.add(attribute.prefix);
37
+ }
38
+ // The prefix list is handled inclusively: a listed prefix is rendered
39
+ // whenever it is in scope, utilized or not.
40
+ for (const prefix of inclusivePrefixes) {
41
+ if (resolvePrefix(element, prefix) !== undefined)
42
+ used.add(prefix);
43
+ }
44
+ // Never declared — the specification binds it.
45
+ used.delete("xml");
46
+ return used;
47
+ }
48
+ function writeElement(element, out, rendered, options) {
49
+ const inclusive = options.inclusivePrefixes ?? [];
50
+ const utilized = [...visiblyUtilized(element, inclusive)].sort(compare);
51
+ const declarations = [];
52
+ const childRendered = new Map(rendered);
53
+ for (const prefix of utilized) {
54
+ const uri = resolvePrefix(element, prefix) ?? "";
55
+ if (prefix === "" && uri === "") {
56
+ // `xmlns=""` is written only to undo a default namespace an output
57
+ // ancestor put in scope. Writing it otherwise is noise the signer
58
+ // did not produce.
59
+ if ((rendered.get("") ?? "") !== "") {
60
+ declarations.push(["", ""]);
61
+ childRendered.set("", "");
62
+ }
63
+ continue;
64
+ }
65
+ if (rendered.get(prefix) !== uri) {
66
+ declarations.push([prefix, uri]);
67
+ childRendered.set(prefix, uri);
68
+ }
69
+ }
70
+ out.push("<", element.qname);
71
+ for (const [prefix, uri] of declarations) {
72
+ out.push(" ", prefix === "" ? "xmlns" : `xmlns:${prefix}`, '="', escapeAttribute(uri), '"');
73
+ }
74
+ for (const attribute of [...element.attributes].sort(byNamespaceThenLocal)) {
75
+ out.push(" ", attribute.qname, '="', escapeAttribute(attribute.value), '"');
76
+ }
77
+ out.push(">");
78
+ for (const child of element.children) {
79
+ if (options.omit?.has(child))
80
+ continue;
81
+ writeNode(child, out, childRendered, options);
82
+ }
83
+ // Empty elements are written as a start/end pair, never self-closed.
84
+ out.push("</", element.qname, ">");
85
+ }
86
+ function writeNode(node, out, rendered, options) {
87
+ switch (node.type) {
88
+ case "element":
89
+ writeElement(node, out, rendered, options);
90
+ return;
91
+ case "text":
92
+ out.push(escapeText(node.value));
93
+ return;
94
+ case "comment":
95
+ if (options.withComments)
96
+ out.push("<!--", node.value, "-->");
97
+ return;
98
+ case "instruction":
99
+ out.push("<?", node.target, node.data === "" ? "" : ` ${node.data}`, "?>");
100
+ return;
101
+ }
102
+ }
103
+ /** Namespace URI first, then local name; an empty URI sorts least. */
104
+ function byNamespaceThenLocal(a, b) {
105
+ const uri = compare(a.namespaceUri, b.namespaceUri);
106
+ return uri !== 0 ? uri : compare(a.local, b.local);
107
+ }
108
+ /** Byte order, which is what the specification means by lexicographic here. */
109
+ function compare(a, b) {
110
+ return a < b ? -1 : a > b ? 1 : 0;
111
+ }
112
+ function escapeText(value) {
113
+ return value
114
+ .replace(/&/g, "&amp;")
115
+ .replace(/</g, "&lt;")
116
+ .replace(/>/g, "&gt;")
117
+ .replace(/\r/g, "&#xD;");
118
+ }
119
+ function escapeAttribute(value) {
120
+ return value
121
+ .replace(/&/g, "&amp;")
122
+ .replace(/</g, "&lt;")
123
+ .replace(/"/g, "&quot;")
124
+ .replace(/\t/g, "&#x9;")
125
+ .replace(/\n/g, "&#xA;")
126
+ .replace(/\r/g, "&#xD;");
127
+ }
128
+ export { XML_NS };
129
+ //# sourceMappingURL=c14n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c14n.js","sourceRoot":"","sources":["../src/c14n.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Author-time config for `config/transit.ts`.
3
+ *
4
+ * import { defineConfig, socials } from '@c9up/transit'
5
+ *
6
+ * export default defineConfig({
7
+ * google: socials.google({
8
+ * clientId: env.get('GOOGLE_CLIENT_ID'),
9
+ * clientSecret: env.get('GOOGLE_CLIENT_SECRET'),
10
+ * callbackUrl: 'https://acme.test/auth/google/callback',
11
+ * }),
12
+ * })
13
+ *
14
+ * The keys are yours. Two entries may reach the same provider with different
15
+ * credentials — a `staff` sign-in and a `customers` one, both on Google — and
16
+ * `use(name)` asks for the key, not for the provider.
17
+ */
18
+ import { type AppleConfig } from "./drivers/AppleDriver.js";
19
+ import { type LdapConfig } from "./drivers/LdapDirectory.js";
20
+ import { type OidcConfig } from "./drivers/OidcDriver.js";
21
+ import { type SamlConfig } from "./drivers/SamlDriver.js";
22
+ import type { OAuthConfig, TransitEntry } from "./types.js";
23
+ /** A provider, built when the manager is. */
24
+ export type TransitDriverFactory = () => TransitEntry;
25
+ /** One declared provider: the driver itself, or a factory answering one. */
26
+ export type TransitProviderEntry = TransitEntry | TransitDriverFactory;
27
+ export type TransitConfig = Record<string, TransitProviderEntry>;
28
+ export declare function defineConfig<T extends TransitConfig>(config: T): T;
29
+ /**
30
+ * The social providers Transit speaks to.
31
+ *
32
+ * Factories are lazy, so a config naming a provider this environment never
33
+ * selects costs nothing to declare.
34
+ */
35
+ /**
36
+ * Any provider that speaks OpenID Connect, from its issuer alone — Keycloak,
37
+ * Auth0, Okta, Entra ID, Authentik, Zitadel, and the rest.
38
+ *
39
+ * work: oidc({
40
+ * issuer: 'https://id.acme.com',
41
+ * clientId: env.get('OIDC_CLIENT_ID'),
42
+ * clientSecret: env.get('OIDC_CLIENT_SECRET'),
43
+ * callbackUrl: 'https://acme.test/auth/work/callback',
44
+ * })
45
+ *
46
+ * The endpoints, the signing keys and the algorithms come from what the
47
+ * provider publishes, so there is nothing else to configure and nothing to
48
+ * update when it rotates a key.
49
+ */
50
+ export declare function oidc(config: OidcConfig): TransitDriverFactory;
51
+ /**
52
+ * A SAML 2.0 identity provider — the enterprise directories that speak it:
53
+ * Okta, Entra ID, ADFS, OneLogin, Shibboleth.
54
+ *
55
+ * corp: saml({
56
+ * entityId: 'https://acme.test/saml',
57
+ * callbackUrl: 'https://acme.test/saml/acs',
58
+ * issuer: 'https://idp.acme.test/metadata',
59
+ * signOnUrl: 'https://idp.acme.test/sso',
60
+ * certificates: [env.get('IDP_CERTIFICATE')],
61
+ * })
62
+ *
63
+ * The certificates come from the provider's metadata and nowhere else: a
64
+ * response is never verified against a key it carries itself.
65
+ */
66
+ export declare function saml(config: SamlConfig): TransitDriverFactory;
67
+ /**
68
+ * An LDAP or Active Directory directory.
69
+ *
70
+ * staff: ldap({
71
+ * url: 'ldaps://directory.acme.test',
72
+ * baseDn: 'dc=acme,dc=test',
73
+ * loginAttribute: 'uid',
74
+ * bindDn: 'cn=reader,dc=acme,dc=test',
75
+ * bindPassword: env.get('LDAP_PASSWORD'),
76
+ * })
77
+ *
78
+ * Reached with `transit.authenticate(name, username, password)`: nothing is
79
+ * redirected, so there is no `begin()` for it.
80
+ */
81
+ export declare function ldap(config: LdapConfig): TransitDriverFactory;
82
+ export declare const socials: {
83
+ /**
84
+ * Sign in with Apple. Required on iOS as soon as another social sign-in is
85
+ * offered.
86
+ *
87
+ * It takes a key rather than a secret — the Services ID, the Team ID, the
88
+ * Key ID and the contents of the `.p8` — and its callback arrives as a
89
+ * POST, because asking for a name forces `response_mode=form_post`. The
90
+ * name comes once, in that POST: read it with `parseAppleUser` and store
91
+ * it, because Apple never sends it again.
92
+ */
93
+ apple(config: AppleConfig): TransitDriverFactory;
94
+ discord(config: OAuthConfig): TransitDriverFactory;
95
+ facebook(config: OAuthConfig): TransitDriverFactory;
96
+ github(config: OAuthConfig): TransitDriverFactory;
97
+ google(config: OAuthConfig): TransitDriverFactory;
98
+ /**
99
+ * LinkedIn through the member API, for an application whose LinkedIn app
100
+ * holds `r_liteprofile` / `r_emailaddress`.
101
+ */
102
+ linkedin(config: OAuthConfig): TransitDriverFactory;
103
+ /** LinkedIn through OpenID Connect — what a new application is issued. */
104
+ linkedinOpenidConnect(config: OAuthConfig): TransitDriverFactory;
105
+ spotify(config: OAuthConfig): TransitDriverFactory;
106
+ /**
107
+ * X through OAuth1 — the older flow, and the one whose profile call returns
108
+ * the address. Its redirect needs a request token from X, so it is reached
109
+ * through `begin()` rather than `redirect()`.
110
+ */
111
+ twitter(config: OAuthConfig): TransitDriverFactory;
112
+ /** X through OAuth2. It requires PKCE, which `begin()` handles. */
113
+ twitterX(config: OAuthConfig): TransitDriverFactory;
114
+ };
115
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,KAAK,WAAW,EAAe,MAAM,0BAA0B,CAAC;AAKzE,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,4BAA4B,CAAC;AAG5E,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,yBAAyB,CAAC;AAItE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,6CAA6C;AAC7C,MAAM,MAAM,oBAAoB,GAAG,MAAM,YAAY,CAAC;AAEtD,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,oBAAoB,CAAC;AAEvE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAEjE,wBAAgB,YAAY,CAAC,CAAC,SAAS,aAAa,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAElE;AAED;;;;;GAKG;AACH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,oBAAoB,CAE7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,oBAAoB,CAE7D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,oBAAoB,CAE7D;AAED,eAAO,MAAM,OAAO;IACnB;;;;;;;;;OASG;kBACW,WAAW,GAAG,oBAAoB;oBAGhC,WAAW,GAAG,oBAAoB;qBAGjC,WAAW,GAAG,oBAAoB;mBAGpC,WAAW,GAAG,oBAAoB;mBAGlC,WAAW,GAAG,oBAAoB;IAGjD;;;OAGG;qBACc,WAAW,GAAG,oBAAoB;IAGnD,0EAA0E;kCAC5C,WAAW,GAAG,oBAAoB;oBAGhD,WAAW,GAAG,oBAAoB;IAGlD;;;;OAIG;oBACa,WAAW,GAAG,oBAAoB;IAGlD,mEAAmE;qBAClD,WAAW,GAAG,oBAAoB;CAGnD,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Author-time config for `config/transit.ts`.
3
+ *
4
+ * import { defineConfig, socials } from '@c9up/transit'
5
+ *
6
+ * export default defineConfig({
7
+ * google: socials.google({
8
+ * clientId: env.get('GOOGLE_CLIENT_ID'),
9
+ * clientSecret: env.get('GOOGLE_CLIENT_SECRET'),
10
+ * callbackUrl: 'https://acme.test/auth/google/callback',
11
+ * }),
12
+ * })
13
+ *
14
+ * The keys are yours. Two entries may reach the same provider with different
15
+ * credentials — a `staff` sign-in and a `customers` one, both on Google — and
16
+ * `use(name)` asks for the key, not for the provider.
17
+ */
18
+ import { AppleDriver } from "./drivers/AppleDriver.js";
19
+ import { DiscordDriver } from "./drivers/DiscordDriver.js";
20
+ import { FacebookDriver } from "./drivers/FacebookDriver.js";
21
+ import { GitHubDriver } from "./drivers/GitHubDriver.js";
22
+ import { GoogleDriver } from "./drivers/GoogleDriver.js";
23
+ import { LdapDirectory } from "./drivers/LdapDirectory.js";
24
+ import { LinkedInDriver } from "./drivers/LinkedInDriver.js";
25
+ import { LinkedInOpenidConnectDriver } from "./drivers/LinkedInOpenidConnectDriver.js";
26
+ import { OidcDriver } from "./drivers/OidcDriver.js";
27
+ import { SamlDriver } from "./drivers/SamlDriver.js";
28
+ import { SpotifyDriver } from "./drivers/SpotifyDriver.js";
29
+ import { TwitterDriver } from "./drivers/TwitterDriver.js";
30
+ import { TwitterXDriver } from "./drivers/TwitterXDriver.js";
31
+ export function defineConfig(config) {
32
+ return config;
33
+ }
34
+ /**
35
+ * The social providers Transit speaks to.
36
+ *
37
+ * Factories are lazy, so a config naming a provider this environment never
38
+ * selects costs nothing to declare.
39
+ */
40
+ /**
41
+ * Any provider that speaks OpenID Connect, from its issuer alone — Keycloak,
42
+ * Auth0, Okta, Entra ID, Authentik, Zitadel, and the rest.
43
+ *
44
+ * work: oidc({
45
+ * issuer: 'https://id.acme.com',
46
+ * clientId: env.get('OIDC_CLIENT_ID'),
47
+ * clientSecret: env.get('OIDC_CLIENT_SECRET'),
48
+ * callbackUrl: 'https://acme.test/auth/work/callback',
49
+ * })
50
+ *
51
+ * The endpoints, the signing keys and the algorithms come from what the
52
+ * provider publishes, so there is nothing else to configure and nothing to
53
+ * update when it rotates a key.
54
+ */
55
+ export function oidc(config) {
56
+ return () => new OidcDriver(config);
57
+ }
58
+ /**
59
+ * A SAML 2.0 identity provider — the enterprise directories that speak it:
60
+ * Okta, Entra ID, ADFS, OneLogin, Shibboleth.
61
+ *
62
+ * corp: saml({
63
+ * entityId: 'https://acme.test/saml',
64
+ * callbackUrl: 'https://acme.test/saml/acs',
65
+ * issuer: 'https://idp.acme.test/metadata',
66
+ * signOnUrl: 'https://idp.acme.test/sso',
67
+ * certificates: [env.get('IDP_CERTIFICATE')],
68
+ * })
69
+ *
70
+ * The certificates come from the provider's metadata and nowhere else: a
71
+ * response is never verified against a key it carries itself.
72
+ */
73
+ export function saml(config) {
74
+ return () => new SamlDriver(config);
75
+ }
76
+ /**
77
+ * An LDAP or Active Directory directory.
78
+ *
79
+ * staff: ldap({
80
+ * url: 'ldaps://directory.acme.test',
81
+ * baseDn: 'dc=acme,dc=test',
82
+ * loginAttribute: 'uid',
83
+ * bindDn: 'cn=reader,dc=acme,dc=test',
84
+ * bindPassword: env.get('LDAP_PASSWORD'),
85
+ * })
86
+ *
87
+ * Reached with `transit.authenticate(name, username, password)`: nothing is
88
+ * redirected, so there is no `begin()` for it.
89
+ */
90
+ export function ldap(config) {
91
+ return () => new LdapDirectory(config);
92
+ }
93
+ export const socials = {
94
+ /**
95
+ * Sign in with Apple. Required on iOS as soon as another social sign-in is
96
+ * offered.
97
+ *
98
+ * It takes a key rather than a secret — the Services ID, the Team ID, the
99
+ * Key ID and the contents of the `.p8` — and its callback arrives as a
100
+ * POST, because asking for a name forces `response_mode=form_post`. The
101
+ * name comes once, in that POST: read it with `parseAppleUser` and store
102
+ * it, because Apple never sends it again.
103
+ */
104
+ apple(config) {
105
+ return () => new AppleDriver(config);
106
+ },
107
+ discord(config) {
108
+ return () => new DiscordDriver(config);
109
+ },
110
+ facebook(config) {
111
+ return () => new FacebookDriver(config);
112
+ },
113
+ github(config) {
114
+ return () => new GitHubDriver(config);
115
+ },
116
+ google(config) {
117
+ return () => new GoogleDriver(config);
118
+ },
119
+ /**
120
+ * LinkedIn through the member API, for an application whose LinkedIn app
121
+ * holds `r_liteprofile` / `r_emailaddress`.
122
+ */
123
+ linkedin(config) {
124
+ return () => new LinkedInDriver(config);
125
+ },
126
+ /** LinkedIn through OpenID Connect — what a new application is issued. */
127
+ linkedinOpenidConnect(config) {
128
+ return () => new LinkedInOpenidConnectDriver(config);
129
+ },
130
+ spotify(config) {
131
+ return () => new SpotifyDriver(config);
132
+ },
133
+ /**
134
+ * X through OAuth1 — the older flow, and the one whose profile call returns
135
+ * the address. Its redirect needs a request token from X, so it is reached
136
+ * through `begin()` rather than `redirect()`.
137
+ */
138
+ twitter(config) {
139
+ return () => new TwitterDriver(config);
140
+ },
141
+ /** X through OAuth2. It requires PKCE, which `begin()` handles. */
142
+ twitterX(config) {
143
+ return () => new TwitterXDriver(config);
144
+ },
145
+ };
146
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `ream configure @c9up/transit` — wire federated sign-in in one command.
3
+ *
4
+ * The provider alone is not enough: it reads `config/transit.ts`, and a package
5
+ * registered without one falls back to a default that is rarely the one an
6
+ * application wants. Writing both together is what makes `ream add` mean
7
+ * installed AND working.
8
+ */
9
+ interface Codemods {
10
+ addProvider(importPath: string): Promise<void>;
11
+ addEnvVars(vars: Record<string, string>): Promise<void>;
12
+ writeFile(filePath: string, content: string, options?: {
13
+ force?: boolean;
14
+ }): Promise<void>;
15
+ }
16
+ export declare function configure(codemods: Codemods): Promise<void>;
17
+ export {};
18
+ //# sourceMappingURL=configure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,UAAU,QAAQ;IACjB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,SAAS,CACR,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;CACjB;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BjE"}