@atproto/oauth-types 0.1.1 → 0.1.2-rc.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"atproto-loopback-client-metadata.d.ts","sourceRoot":"","sources":["../src/atproto-loopback-client-metadata.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAGrE,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,GACf,wBAAwB,CAuB1B"}
1
+ {"version":3,"file":"atproto-loopback-client-metadata.d.ts","sourceRoot":"","sources":["../src/atproto-loopback-client-metadata.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAGrE,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,GACf,wBAAwB,CA8B1B"}
@@ -8,15 +8,21 @@ function atprotoLoopbackClientMetadata(clientId) {
8
8
  throw new TypeError(`Invalid loopback client ID ${clientId}`);
9
9
  }
10
10
  const { origin, pathname, searchParams } = (0, oauth_client_id_url_js_1.parseOAuthClientIdUrl)(clientId);
11
+ for (const name of searchParams.keys()) {
12
+ if (name !== 'redirect_uri') {
13
+ throw new TypeError(`Invalid query parameter ${name} in client ID`);
14
+ }
15
+ }
16
+ const redirectUris = searchParams.getAll('redirect_uri');
11
17
  return {
12
18
  client_id: clientId,
13
19
  client_name: 'Loopback client',
14
20
  response_types: ['code id_token', 'code'],
15
21
  grant_types: ['authorization_code', 'implicit', 'refresh_token'],
16
22
  scope: 'openid profile offline_access',
17
- redirect_uris: searchParams.has('redirect_uri')
18
- ? searchParams.getAll('redirect_uri')
19
- : ['127.0.0.1', '[::1]'].map((ip) => Object.assign(new URL(pathname, origin), { hostname: ip }).href),
23
+ redirect_uris: (redirectUris.length
24
+ ? redirectUris
25
+ : ['127.0.0.1', '[::1]'].map((ip) => Object.assign(new URL(pathname, origin), { hostname: ip }).href)),
20
26
  token_endpoint_auth_method: 'none',
21
27
  application_type: 'native',
22
28
  dpop_bound_access_tokens: true,
@@ -1 +1 @@
1
- {"version":3,"file":"atproto-loopback-client-metadata.js","sourceRoot":"","sources":["../src/atproto-loopback-client-metadata.ts"],"names":[],"mappings":";;;AAAA,+EAAuE;AAEvE,qEAAgE;AAEhE,SAAgB,6BAA6B,CAC3C,QAAgB;IAEhB,IAAI,CAAC,IAAA,qDAAuB,EAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,SAAS,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAA;IAC/D,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAA,8CAAqB,EAAC,QAAQ,CAAC,CAAA;IAE1E,OAAO;QACL,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,iBAAiB;QAC9B,cAAc,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC;QACzC,WAAW,EAAE,CAAC,oBAAoB,EAAE,UAAU,EAAE,eAAe,CAAC;QAChE,KAAK,EAAE,+BAA+B;QACtC,aAAa,EAAE,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC;YAC7C,CAAC,CAAE,YAAY,CAAC,MAAM,CAAC,cAAc,CAA2B;YAChE,CAAC,CAAE,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,GAAG,CACzB,CAAC,EAAE,EAAE,EAAE,CACL,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CACxC;QAC/B,0BAA0B,EAAE,MAAM;QAClC,gBAAgB,EAAE,QAAQ;QAC1B,wBAAwB,EAAE,IAAI;KAC/B,CAAA;AACH,CAAC;AAzBD,sEAyBC"}
1
+ {"version":3,"file":"atproto-loopback-client-metadata.js","sourceRoot":"","sources":["../src/atproto-loopback-client-metadata.ts"],"names":[],"mappings":";;;AAAA,+EAAuE;AAEvE,qEAAgE;AAEhE,SAAgB,6BAA6B,CAC3C,QAAgB;IAEhB,IAAI,CAAC,IAAA,qDAAuB,EAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,SAAS,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAA;IAC/D,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAA,8CAAqB,EAAC,QAAQ,CAAC,CAAA;IAE1E,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5B,MAAM,IAAI,SAAS,CAAC,2BAA2B,IAAI,eAAe,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;IACD,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAExD,OAAO;QACL,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,iBAAiB;QAC9B,cAAc,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC;QACzC,WAAW,EAAE,CAAC,oBAAoB,EAAE,UAAU,EAAE,eAAe,CAAC;QAChE,KAAK,EAAE,+BAA+B;QACtC,aAAa,EAAE,CAAC,YAAY,CAAC,MAAM;YACjC,CAAC,CAAC,YAAY;YACd,CAAC,CAAE,CAAC,WAAW,EAAE,OAAO,CAAW,CAAC,GAAG,CACnC,CAAC,EAAE,EAAE,EAAE,CACL,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAClE,CAA0B;QAC/B,0BAA0B,EAAE,MAAM;QAClC,gBAAgB,EAAE,QAAQ;QAC1B,wBAAwB,EAAE,IAAI;KAC/B,CAAA;AACH,CAAC;AAhCD,sEAgCC"}
@@ -1,3 +1,9 @@
1
+ /**
2
+ * A variable that allows to determine if unsecure origins should be allowed
3
+ * in OAuth related URI's. This variable is only set to `true` when NODE_ENV
4
+ * is either `development` or `test`.
5
+ */
6
+ export declare const ALLOW_UNSECURE_ORIGINS: boolean;
1
7
  export declare const CLIENT_ASSERTION_TYPE_JWT_BEARER = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
2
8
  export declare const OAUTH_AUTHENTICATED_ENDPOINT_NAMES: readonly ["token", "revocation", "introspection", "pushed_authorization_request"];
3
9
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gCAAgC,2DACa,CAAA;AAE1D,eAAO,MAAM,kCAAkC,mFAKrC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,SAS/B,CAAA;AAEJ,eAAO,MAAM,gCAAgC,2DACa,CAAA;AAE1D,eAAO,MAAM,kCAAkC,mFAKrC,CAAA"}
package/dist/constants.js CHANGED
@@ -1,6 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OAUTH_AUTHENTICATED_ENDPOINT_NAMES = exports.CLIENT_ASSERTION_TYPE_JWT_BEARER = void 0;
3
+ exports.OAUTH_AUTHENTICATED_ENDPOINT_NAMES = exports.CLIENT_ASSERTION_TYPE_JWT_BEARER = exports.ALLOW_UNSECURE_ORIGINS = void 0;
4
+ /**
5
+ * A variable that allows to determine if unsecure origins should be allowed
6
+ * in OAuth related URI's. This variable is only set to `true` when NODE_ENV
7
+ * is either `development` or `test`.
8
+ */
9
+ exports.ALLOW_UNSECURE_ORIGINS = (() => {
10
+ // try/catch to support running in a browser, including when process.env is
11
+ // shimmed (e.g. by webpack)
12
+ try {
13
+ const env = process.env.NODE_ENV;
14
+ return env === 'development' || env === 'test';
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ })();
4
20
  exports.CLIENT_ASSERTION_TYPE_JWT_BEARER = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';
5
21
  exports.OAUTH_AUTHENTICATED_ENDPOINT_NAMES = [
6
22
  'token',
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,gCAAgC,GAC3C,wDAAwD,CAAA;AAE7C,QAAA,kCAAkC,GAAG;IAChD,OAAO;IACP,YAAY;IACZ,eAAe;IACf,8BAA8B;CACtB,CAAA"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACU,QAAA,sBAAsB,GAAG,CAAC,GAAG,EAAE;IAC1C,2EAA2E;IAC3E,4BAA4B;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;QAChC,OAAO,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,MAAM,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAC,EAAE,CAAA;AAES,QAAA,gCAAgC,GAC3C,wDAAwD,CAAA;AAE7C,QAAA,kCAAkC,GAAG;IAChD,OAAO;IACP,YAAY;IACZ,eAAe;IACf,8BAA8B;CACtB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-issuer-identifier.d.ts","sourceRoot":"","sources":["../src/oauth-issuer-identifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAavB,eAAO,MAAM,2BAA2B,2CA+CpC,CAAA"}
1
+ {"version":3,"file":"oauth-issuer-identifier.d.ts","sourceRoot":"","sources":["../src/oauth-issuer-identifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,2BAA2B,2CAoDpC,CAAA"}
@@ -2,20 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.oauthIssuerIdentifierSchema = void 0;
4
4
  const zod_1 = require("zod");
5
- // try/catch to support running in a browser, including when process.env is
6
- // shimmed (e.g. by webpack)
7
- const ALLOW_INSECURE = (() => {
8
- try {
9
- const env = process.env.NODE_ENV;
10
- return env === 'development' || env === 'test';
11
- }
12
- catch {
13
- return false;
14
- }
15
- })();
5
+ const constants_js_1 = require("./constants.js");
6
+ const util_js_1 = require("./util.js");
16
7
  exports.oauthIssuerIdentifierSchema = zod_1.z
17
8
  .string()
18
- .url()
19
9
  .superRefine((value, ctx) => {
20
10
  // Validate the issuer (MIX-UP attacks)
21
11
  if (value.endsWith('/')) {
@@ -24,9 +14,15 @@ exports.oauthIssuerIdentifierSchema = zod_1.z
24
14
  message: 'Issuer URL must not end with a slash',
25
15
  });
26
16
  }
27
- const url = new URL(value);
17
+ const url = (0, util_js_1.safeUrl)(value);
18
+ if (!url) {
19
+ return ctx.addIssue({
20
+ code: zod_1.z.ZodIssueCode.custom,
21
+ message: 'Invalid url',
22
+ });
23
+ }
28
24
  if (url.protocol !== 'https:') {
29
- if (ALLOW_INSECURE && url.protocol === 'http:') {
25
+ if (constants_js_1.ALLOW_UNSECURE_ORIGINS && url.protocol === 'http:') {
30
26
  // We'll allow HTTP in development mode
31
27
  }
32
28
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-issuer-identifier.js","sourceRoot":"","sources":["../src/oauth-issuer-identifier.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEvB,2EAA2E;AAC3E,4BAA4B;AAC5B,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;QAChC,OAAO,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,MAAM,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAC,EAAE,CAAA;AAES,QAAA,2BAA2B,GAAG,OAAC;KACzC,MAAM,EAAE;KACR,GAAG,EAAE;KACL,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC1B,uCAAuC;IAEvC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,sCAAsC;SAChD,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAE1B,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,cAAc,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAC/C,uCAAuC;QACzC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;gBAC3B,OAAO,EAAE,6BAA6B;aACvC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjC,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,oDAAoD;SAC9D,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3B,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,iDAAiD;SAC3D,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAA;IACnE,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;QAC7B,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,0CAA0C;SACpD,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"oauth-issuer-identifier.js","sourceRoot":"","sources":["../src/oauth-issuer-identifier.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AACvB,iDAAuD;AACvD,uCAAmC;AAEtB,QAAA,2BAA2B,GAAG,OAAC;KACzC,MAAM,EAAE;KACR,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC1B,uCAAuC;IAEvC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,sCAAsC;SAChD,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAA,iBAAO,EAAC,KAAK,CAAC,CAAA;IAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,GAAG,CAAC,QAAQ,CAAC;YAClB,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,aAAa;SACvB,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,qCAAsB,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACvD,uCAAuC;QACzC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;gBAC3B,OAAO,EAAE,6BAA6B;aACvC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjC,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,oDAAoD;SAC9D,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3B,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,iDAAiD;SAC3D,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAA;IACnE,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;QAC7B,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,0CAA0C;SACpD,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAC,CAAA"}
package/dist/util.d.ts CHANGED
@@ -2,4 +2,5 @@ export declare function isIP(hostname: string): boolean;
2
2
  export type LoopbackHost = 'localhost' | '127.0.0.1' | '[::1]';
3
3
  export declare function isLoopbackHost(host: unknown): host is LoopbackHost;
4
4
  export declare function isLoopbackUrl(input: URL | string): boolean;
5
+ export declare function safeUrl(input: URL | string): URL | null;
5
6
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,WAQpC;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;AAE9D,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAElE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAG1D"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,WAQpC;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;AAE9D,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAElE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAG1D;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,GAAG,GAAG,IAAI,CAMvD"}
package/dist/util.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isLoopbackUrl = exports.isLoopbackHost = exports.isIP = void 0;
3
+ exports.safeUrl = exports.isLoopbackUrl = exports.isLoopbackHost = exports.isIP = void 0;
4
4
  function isIP(hostname) {
5
5
  // IPv4
6
6
  if (hostname.match(/^\d+\.\d+\.\d+\.\d+$/))
@@ -20,4 +20,13 @@ function isLoopbackUrl(input) {
20
20
  return isLoopbackHost(url.hostname);
21
21
  }
22
22
  exports.isLoopbackUrl = isLoopbackUrl;
23
+ function safeUrl(input) {
24
+ try {
25
+ return new URL(input);
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ exports.safeUrl = safeUrl;
23
32
  //# sourceMappingURL=util.js.map
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAAA,SAAgB,IAAI,CAAC,QAAgB;IACnC,OAAO;IACP,IAAI,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvD,OAAO;IACP,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAEnE,OAAO,KAAK,CAAA;AACd,CAAC;AARD,oBAQC;AAID,SAAgB,cAAc,CAAC,IAAa;IAC1C,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,OAAO,CAAA;AACzE,CAAC;AAFD,wCAEC;AAED,SAAgB,aAAa,CAAC,KAAmB;IAC/C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAC9D,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC;AAHD,sCAGC"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAAA,SAAgB,IAAI,CAAC,QAAgB;IACnC,OAAO;IACP,IAAI,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvD,OAAO;IACP,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAEnE,OAAO,KAAK,CAAA;AACd,CAAC;AARD,oBAQC;AAID,SAAgB,cAAc,CAAC,IAAa;IAC1C,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,OAAO,CAAA;AACzE,CAAC;AAFD,wCAEC;AAED,SAAgB,aAAa,CAAC,KAAmB;IAC/C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAC9D,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC;AAHD,sCAGC;AAED,SAAgB,OAAO,CAAC,KAAmB;IACzC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAND,0BAMC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/oauth-types",
3
- "version": "0.1.1",
3
+ "version": "0.1.2-rc.1",
4
4
  "license": "MIT",
5
5
  "description": "OAuth typing & validation library",
6
6
  "keywords": [
@@ -11,18 +11,25 @@ export function atprotoLoopbackClientMetadata(
11
11
 
12
12
  const { origin, pathname, searchParams } = parseOAuthClientIdUrl(clientId)
13
13
 
14
+ for (const name of searchParams.keys()) {
15
+ if (name !== 'redirect_uri') {
16
+ throw new TypeError(`Invalid query parameter ${name} in client ID`)
17
+ }
18
+ }
19
+ const redirectUris = searchParams.getAll('redirect_uri')
20
+
14
21
  return {
15
22
  client_id: clientId,
16
23
  client_name: 'Loopback client',
17
24
  response_types: ['code id_token', 'code'],
18
25
  grant_types: ['authorization_code', 'implicit', 'refresh_token'],
19
26
  scope: 'openid profile offline_access',
20
- redirect_uris: searchParams.has('redirect_uri')
21
- ? (searchParams.getAll('redirect_uri') as [string, ...string[]])
22
- : (['127.0.0.1', '[::1]'].map(
27
+ redirect_uris: (redirectUris.length
28
+ ? redirectUris
29
+ : (['127.0.0.1', '[::1]'] as const).map(
23
30
  (ip) =>
24
31
  Object.assign(new URL(pathname, origin), { hostname: ip }).href,
25
- ) as [string, ...string[]]),
32
+ )) as [string, ...string[]],
26
33
  token_endpoint_auth_method: 'none',
27
34
  application_type: 'native',
28
35
  dpop_bound_access_tokens: true,
package/src/constants.ts CHANGED
@@ -1,3 +1,19 @@
1
+ /**
2
+ * A variable that allows to determine if unsecure origins should be allowed
3
+ * in OAuth related URI's. This variable is only set to `true` when NODE_ENV
4
+ * is either `development` or `test`.
5
+ */
6
+ export const ALLOW_UNSECURE_ORIGINS = (() => {
7
+ // try/catch to support running in a browser, including when process.env is
8
+ // shimmed (e.g. by webpack)
9
+ try {
10
+ const env = process.env.NODE_ENV
11
+ return env === 'development' || env === 'test'
12
+ } catch {
13
+ return false
14
+ }
15
+ })()
16
+
1
17
  export const CLIENT_ASSERTION_TYPE_JWT_BEARER =
2
18
  'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
3
19
 
@@ -1,19 +1,9 @@
1
1
  import { z } from 'zod'
2
-
3
- // try/catch to support running in a browser, including when process.env is
4
- // shimmed (e.g. by webpack)
5
- const ALLOW_INSECURE = (() => {
6
- try {
7
- const env = process.env.NODE_ENV
8
- return env === 'development' || env === 'test'
9
- } catch {
10
- return false
11
- }
12
- })()
2
+ import { ALLOW_UNSECURE_ORIGINS } from './constants.js'
3
+ import { safeUrl } from './util.js'
13
4
 
14
5
  export const oauthIssuerIdentifierSchema = z
15
6
  .string()
16
- .url()
17
7
  .superRefine((value, ctx) => {
18
8
  // Validate the issuer (MIX-UP attacks)
19
9
 
@@ -24,10 +14,16 @@ export const oauthIssuerIdentifierSchema = z
24
14
  })
25
15
  }
26
16
 
27
- const url = new URL(value)
17
+ const url = safeUrl(value)
18
+ if (!url) {
19
+ return ctx.addIssue({
20
+ code: z.ZodIssueCode.custom,
21
+ message: 'Invalid url',
22
+ })
23
+ }
28
24
 
29
25
  if (url.protocol !== 'https:') {
30
- if (ALLOW_INSECURE && url.protocol === 'http:') {
26
+ if (ALLOW_UNSECURE_ORIGINS && url.protocol === 'http:') {
31
27
  // We'll allow HTTP in development mode
32
28
  } else {
33
29
  ctx.addIssue({
package/src/util.ts CHANGED
@@ -18,3 +18,11 @@ export function isLoopbackUrl(input: URL | string): boolean {
18
18
  const url = typeof input === 'string' ? new URL(input) : input
19
19
  return isLoopbackHost(url.hostname)
20
20
  }
21
+
22
+ export function safeUrl(input: URL | string): URL | null {
23
+ try {
24
+ return new URL(input)
25
+ } catch {
26
+ return null
27
+ }
28
+ }