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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0",
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
+ }