@atproto/identity 0.2.1 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @atproto/identity
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1788](https://github.com/bluesky-social/atproto/pull/1788) [`84e2d4d2`](https://github.com/bluesky-social/atproto/commit/84e2d4d2b6694f344d80c18672c78b650189d423) Thanks [@bnewbold](https://github.com/bnewbold)! - update license to "MIT or Apache2"
8
+
9
+ - Updated dependencies [[`84e2d4d2`](https://github.com/bluesky-social/atproto/commit/84e2d4d2b6694f344d80c18672c78b650189d423)]:
10
+ - @atproto/common-web@0.2.3
11
+ - @atproto/crypto@0.2.3
12
+
13
+ ## 0.3.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [#1773](https://github.com/bluesky-social/atproto/pull/1773) [`bb039d8e`](https://github.com/bluesky-social/atproto/commit/bb039d8e4ce5b7f70c4f3e86d1327e210ef24dc3) Thanks [@dholms](https://github.com/dholms)! - Pass stale did doc into refresh cache functions
18
+
19
+ ### Patch Changes
20
+
21
+ - [`35d108ce`](https://github.com/bluesky-social/atproto/commit/35d108ce94866ce1b3d147cd0620a0ba1c4ebcd7) Thanks [@devinivy](https://github.com/devinivy)! - Allow pds to serve did doc with credentials, API client to respect PDS listed in the did doc.
22
+
23
+ - Updated dependencies [[`35d108ce`](https://github.com/bluesky-social/atproto/commit/35d108ce94866ce1b3d147cd0620a0ba1c4ebcd7)]:
24
+ - @atproto/common-web@0.2.2
25
+
3
26
  ## 0.2.1
4
27
 
5
28
  ### Patch Changes
package/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Dual MIT/Apache-2.0 License
2
+
3
+ Copyright (c) 2022-2023 Bluesky PBC, and Contributors
4
+
5
+ Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
6
+
7
+ Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
package/README.md CHANGED
@@ -37,4 +37,9 @@ if (data.handle != handle) {
37
37
 
38
38
  ## License
39
39
 
40
- MIT License
40
+ This project is dual-licensed under MIT and Apache 2.0 terms:
41
+
42
+ - MIT license ([LICENSE-MIT.txt](https://github.com/bluesky-social/atproto/blob/main/LICENSE-MIT.txt) or http://opensource.org/licenses/MIT)
43
+ - Apache License, Version 2.0, ([LICENSE-APACHE.txt](https://github.com/bluesky-social/atproto/blob/main/LICENSE-APACHE.txt) or http://www.apache.org/licenses/LICENSE-2.0)
44
+
45
+ Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
@@ -1,9 +1,7 @@
1
1
  import { DidDocument, AtprotoData } from '../types';
2
- export declare const getDid: (doc: DidDocument) => string;
2
+ import { getDid, getHandle, getPdsEndpoint, getFeedGenEndpoint, getNotifEndpoint } from '@atproto/common-web';
3
+ export { getDid, getHandle, getPdsEndpoint as getPds, getFeedGenEndpoint as getFeedGen, getNotifEndpoint as getNotif, };
3
4
  export declare const getKey: (doc: DidDocument) => string | undefined;
4
- export declare const getHandle: (doc: DidDocument) => string | undefined;
5
- export declare const getPds: (doc: DidDocument) => string | undefined;
6
- export declare const getFeedGen: (doc: DidDocument) => string | undefined;
7
- export declare const getNotif: (doc: DidDocument) => string | undefined;
8
5
  export declare const parseToAtprotoDocument: (doc: DidDocument) => Partial<AtprotoData>;
9
6
  export declare const ensureAtpDocument: (doc: DidDocument) => AtprotoData;
7
+ export declare const ensureAtprotoKey: (doc: DidDocument) => string;
@@ -1,11 +1,11 @@
1
- import { DidCache, AtprotoData, DidDocument } from '../types';
1
+ import { DidCache, AtprotoData, DidDocument, CacheResult } from '../types';
2
2
  export declare abstract class BaseResolver {
3
3
  cache?: DidCache | undefined;
4
4
  constructor(cache?: DidCache | undefined);
5
5
  abstract resolveNoCheck(did: string): Promise<unknown | null>;
6
6
  validateDidDoc(did: string, val: unknown): DidDocument;
7
7
  resolveNoCache(did: string): Promise<DidDocument | null>;
8
- refreshCache(did: string): Promise<void>;
8
+ refreshCache(did: string, prevResult?: CacheResult): Promise<void>;
9
9
  resolve(did: string, forceRefresh?: boolean): Promise<DidDocument | null>;
10
10
  ensureResolve(did: string, forceRefresh?: boolean): Promise<DidDocument>;
11
11
  resolveAtprotoData(did: string, forceRefresh?: boolean): Promise<AtprotoData>;
package/dist/index.js CHANGED
@@ -21170,15 +21170,14 @@ __export(src_exports3, {
21170
21170
  UnsupportedDidWebPathError: () => UnsupportedDidWebPathError,
21171
21171
  didDocument: () => didDocument,
21172
21172
  ensureAtpDocument: () => ensureAtpDocument,
21173
+ ensureAtprotoKey: () => ensureAtprotoKey,
21173
21174
  getDid: () => getDid,
21174
- getFeedGen: () => getFeedGen,
21175
+ getFeedGen: () => getFeedGenEndpoint,
21175
21176
  getHandle: () => getHandle,
21176
21177
  getKey: () => getKey,
21177
- getNotif: () => getNotif,
21178
- getPds: () => getPds,
21179
- parseToAtprotoDocument: () => parseToAtprotoDocument,
21180
- service: () => service,
21181
- verificationMethod: () => verificationMethod
21178
+ getNotif: () => getNotifEndpoint,
21179
+ getPds: () => getPdsEndpoint,
21180
+ parseToAtprotoDocument: () => parseToAtprotoDocument
21182
21181
  });
21183
21182
  module.exports = __toCommonJS(src_exports3);
21184
21183
 
@@ -24177,16 +24176,18 @@ var decompressPubkey2 = (compressed) => {
24177
24176
  };
24178
24177
 
24179
24178
  // ../crypto/src/p256/operations.ts
24180
- var verifyDidSig = async (did, data, sig) => {
24179
+ var verifyDidSig = async (did, data, sig, opts) => {
24181
24180
  const { jwtAlg, keyBytes } = parseDidKey(did);
24182
24181
  if (jwtAlg !== P256_JWT_ALG) {
24183
24182
  throw new Error(`Not a P-256 did:key: ${did}`);
24184
24183
  }
24185
- return verifySig(keyBytes, data, sig);
24184
+ return verifySig(keyBytes, data, sig, opts);
24186
24185
  };
24187
- var verifySig = async (publicKey, data, sig) => {
24186
+ var verifySig = async (publicKey, data, sig, opts) => {
24188
24187
  const msgHash = await sha2562(data);
24189
- return p256.verify(sig, msgHash, publicKey, { lowS: true });
24188
+ return p256.verify(sig, msgHash, publicKey, {
24189
+ lowS: opts?.lowS ?? true
24190
+ });
24190
24191
  };
24191
24192
 
24192
24193
  // ../crypto/src/p256/plugin.ts
@@ -24198,16 +24199,18 @@ var p256Plugin = {
24198
24199
  var plugin_default = p256Plugin;
24199
24200
 
24200
24201
  // ../crypto/src/secp256k1/operations.ts
24201
- var verifyDidSig2 = async (did, data, sig) => {
24202
+ var verifyDidSig2 = async (did, data, sig, opts) => {
24202
24203
  const { jwtAlg, keyBytes } = parseDidKey(did);
24203
24204
  if (jwtAlg !== SECP256K1_JWT_ALG) {
24204
24205
  throw new Error(`Not a secp256k1 did:key: ${did}`);
24205
24206
  }
24206
- return verifySig2(keyBytes, data, sig);
24207
+ return verifySig2(keyBytes, data, sig, opts);
24207
24208
  };
24208
- var verifySig2 = async (publicKey, data, sig) => {
24209
+ var verifySig2 = async (publicKey, data, sig, opts) => {
24209
24210
  const msgHash = await sha2562(data);
24210
- return secp256k1.verify(sig, msgHash, publicKey, { lowS: true });
24211
+ return secp256k1.verify(sig, msgHash, publicKey, {
24212
+ lowS: opts?.lowS ?? true
24213
+ });
24211
24214
  };
24212
24215
 
24213
24216
  // ../crypto/src/secp256k1/plugin.ts
@@ -24296,13 +24299,13 @@ var multibaseToBytes = (mb) => {
24296
24299
  };
24297
24300
 
24298
24301
  // ../crypto/src/verify.ts
24299
- var verifySignature = (didKey, data, sig) => {
24302
+ var verifySignature = (didKey, data, sig, opts) => {
24300
24303
  const parsed = parseDidKey(didKey);
24301
24304
  const plugin = plugins_default.find((p) => p.jwtAlg === parsed.jwtAlg);
24302
24305
  if (!plugin) {
24303
- throw new Error(`Unsupported signature alg: :${parsed.jwtAlg}`);
24306
+ throw new Error(`Unsupported signature alg: ${parsed.jwtAlg}`);
24304
24307
  }
24305
- return plugin.verifySignature(didKey, data, sig);
24308
+ return plugin.verifySignature(didKey, data, sig, opts);
24306
24309
  };
24307
24310
 
24308
24311
  // ../common-web/src/check.ts
@@ -27950,26 +27953,7 @@ var DAY = HOUR * 24;
27950
27953
  // ../common-web/src/strings.ts
27951
27954
  var import_graphemer = __toESM(require_lib());
27952
27955
 
27953
- // src/types.ts
27954
- var verificationMethod = objectType({
27955
- id: stringType(),
27956
- type: stringType(),
27957
- controller: stringType(),
27958
- publicKeyMultibase: stringType().optional()
27959
- });
27960
- var service = objectType({
27961
- id: stringType(),
27962
- type: stringType(),
27963
- serviceEndpoint: unionType([stringType(), recordType(unknownType())])
27964
- });
27965
- var didDocument = objectType({
27966
- id: stringType(),
27967
- alsoKnownAs: arrayType(stringType()).optional(),
27968
- verificationMethod: arrayType(verificationMethod).optional(),
27969
- service: arrayType(service).optional()
27970
- });
27971
-
27972
- // src/did/atproto-data.ts
27956
+ // ../common-web/src/did-doc.ts
27973
27957
  var getDid = (doc) => {
27974
27958
  const id = doc.id;
27975
27959
  if (typeof id !== "string") {
@@ -27977,7 +27961,16 @@ var getDid = (doc) => {
27977
27961
  }
27978
27962
  return id;
27979
27963
  };
27980
- var getKey = (doc) => {
27964
+ var getHandle = (doc) => {
27965
+ const aka = doc.alsoKnownAs;
27966
+ if (!aka)
27967
+ return void 0;
27968
+ const found = aka.find((name2) => name2.startsWith("at://"));
27969
+ if (!found)
27970
+ return void 0;
27971
+ return found.slice(5);
27972
+ };
27973
+ var getSigningKey = (doc) => {
27981
27974
  const did = getDid(doc);
27982
27975
  let keys = doc.verificationMethod;
27983
27976
  if (!keys)
@@ -27988,56 +27981,109 @@ var getKey = (doc) => {
27988
27981
  keys = [keys];
27989
27982
  }
27990
27983
  const found = keys.find((key) => key.id === "#atproto" || key.id === `${did}#atproto`);
27991
- if (!found)
27992
- return void 0;
27993
- if (!found.publicKeyMultibase)
27994
- return void 0;
27995
- const keyBytes = multibaseToBytes(found.publicKeyMultibase);
27996
- let didKey = void 0;
27997
- if (found.type === "EcdsaSecp256r1VerificationKey2019") {
27998
- didKey = formatDidKey(P256_JWT_ALG, keyBytes);
27999
- } else if (found.type === "EcdsaSecp256k1VerificationKey2019") {
28000
- didKey = formatDidKey(SECP256K1_JWT_ALG, keyBytes);
28001
- } else if (found.type === "Multikey") {
28002
- const parsed = parseMultikey(found.publicKeyMultibase);
28003
- didKey = formatDidKey(parsed.jwtAlg, parsed.keyBytes);
28004
- }
28005
- return didKey;
28006
- };
28007
- var getHandle = (doc) => {
28008
- const aka = doc.alsoKnownAs;
28009
- if (!aka)
28010
- return void 0;
28011
- const found = aka.find((name2) => name2.startsWith("at://"));
28012
- if (!found)
27984
+ if (!found?.publicKeyMultibase)
28013
27985
  return void 0;
28014
- return found.slice(5);
27986
+ return {
27987
+ type: found.type,
27988
+ publicKeyMultibase: found.publicKeyMultibase
27989
+ };
28015
27990
  };
28016
- var getPds = (doc) => {
27991
+ var getPdsEndpoint = (doc) => {
28017
27992
  return getServiceEndpoint(doc, {
28018
27993
  id: "#atproto_pds",
28019
27994
  type: "AtprotoPersonalDataServer"
28020
27995
  });
28021
27996
  };
28022
- var getFeedGen = (doc) => {
27997
+ var getFeedGenEndpoint = (doc) => {
28023
27998
  return getServiceEndpoint(doc, {
28024
27999
  id: "#bsky_fg",
28025
28000
  type: "BskyFeedGenerator"
28026
28001
  });
28027
28002
  };
28028
- var getNotif = (doc) => {
28003
+ var getNotifEndpoint = (doc) => {
28029
28004
  return getServiceEndpoint(doc, {
28030
28005
  id: "#bsky_notif",
28031
28006
  type: "BskyNotificationService"
28032
28007
  });
28033
28008
  };
28009
+ var getServiceEndpoint = (doc, opts) => {
28010
+ const did = getDid(doc);
28011
+ let services = doc.service;
28012
+ if (!services)
28013
+ return void 0;
28014
+ if (typeof services !== "object")
28015
+ return void 0;
28016
+ if (!Array.isArray(services)) {
28017
+ services = [services];
28018
+ }
28019
+ const found = services.find((service2) => service2.id === opts.id || service2.id === `${did}${opts.id}`);
28020
+ if (!found)
28021
+ return void 0;
28022
+ if (found.type !== opts.type) {
28023
+ return void 0;
28024
+ }
28025
+ if (typeof found.serviceEndpoint !== "string") {
28026
+ return void 0;
28027
+ }
28028
+ return validateUrl(found.serviceEndpoint);
28029
+ };
28030
+ var validateUrl = (urlStr) => {
28031
+ let url;
28032
+ try {
28033
+ url = new URL(urlStr);
28034
+ } catch {
28035
+ return void 0;
28036
+ }
28037
+ if (!["http:", "https:"].includes(url.protocol)) {
28038
+ return void 0;
28039
+ } else if (!url.hostname) {
28040
+ return void 0;
28041
+ } else {
28042
+ return urlStr;
28043
+ }
28044
+ };
28045
+ var verificationMethod = z.object({
28046
+ id: z.string(),
28047
+ type: z.string(),
28048
+ controller: z.string(),
28049
+ publicKeyMultibase: z.string().optional()
28050
+ });
28051
+ var service = z.object({
28052
+ id: z.string(),
28053
+ type: z.string(),
28054
+ serviceEndpoint: z.union([z.string(), z.record(z.unknown())])
28055
+ });
28056
+ var didDocument = z.object({
28057
+ id: z.string(),
28058
+ alsoKnownAs: z.array(z.string()).optional(),
28059
+ verificationMethod: z.array(verificationMethod).optional(),
28060
+ service: z.array(service).optional()
28061
+ });
28062
+
28063
+ // src/did/atproto-data.ts
28064
+ var getKey = (doc) => {
28065
+ const key = getSigningKey(doc);
28066
+ if (!key)
28067
+ return void 0;
28068
+ const keyBytes = multibaseToBytes(key.publicKeyMultibase);
28069
+ let didKey = void 0;
28070
+ if (key.type === "EcdsaSecp256r1VerificationKey2019") {
28071
+ didKey = formatDidKey(P256_JWT_ALG, keyBytes);
28072
+ } else if (key.type === "EcdsaSecp256k1VerificationKey2019") {
28073
+ didKey = formatDidKey(SECP256K1_JWT_ALG, keyBytes);
28074
+ } else if (key.type === "Multikey") {
28075
+ const parsed = parseMultikey(key.publicKeyMultibase);
28076
+ didKey = formatDidKey(parsed.jwtAlg, parsed.keyBytes);
28077
+ }
28078
+ return didKey;
28079
+ };
28034
28080
  var parseToAtprotoDocument = (doc) => {
28035
28081
  const did = getDid(doc);
28036
28082
  return {
28037
28083
  did,
28038
28084
  signingKey: getKey(doc),
28039
28085
  handle: getHandle(doc),
28040
- pds: getPds(doc)
28086
+ pds: getPdsEndpoint(doc)
28041
28087
  };
28042
28088
  };
28043
28089
  var ensureAtpDocument = (doc) => {
@@ -28056,36 +28102,12 @@ var ensureAtpDocument = (doc) => {
28056
28102
  }
28057
28103
  return { did, signingKey, handle, pds };
28058
28104
  };
28059
- var validateUrl = (url) => {
28060
- const { hostname, protocol } = new URL(url);
28061
- if (!["http:", "https:"].includes(protocol)) {
28062
- throw new Error("Invalid pds protocol");
28063
- }
28064
- if (!hostname) {
28065
- throw new Error("Invalid pds hostname");
28066
- }
28067
- };
28068
- var getServiceEndpoint = (doc, opts) => {
28069
- const did = getDid(doc);
28070
- let services = doc.service;
28071
- if (!services)
28072
- return void 0;
28073
- if (typeof services !== "object")
28074
- return void 0;
28075
- if (!Array.isArray(services)) {
28076
- services = [services];
28077
- }
28078
- const found = services.find((service2) => service2.id === opts.id || service2.id === `${did}${opts.id}`);
28079
- if (!found)
28080
- return void 0;
28081
- if (found.type !== opts.type) {
28082
- return void 0;
28083
- }
28084
- if (typeof found.serviceEndpoint !== "string") {
28085
- return void 0;
28105
+ var ensureAtprotoKey = (doc) => {
28106
+ const { signingKey } = parseToAtprotoDocument(doc);
28107
+ if (!signingKey) {
28108
+ throw new Error(`Could not parse signingKey from doc: ${doc}`);
28086
28109
  }
28087
- validateUrl(found.serviceEndpoint);
28088
- return found.serviceEndpoint;
28110
+ return signingKey;
28089
28111
  };
28090
28112
 
28091
28113
  // src/errors.ts
@@ -28141,16 +28163,17 @@ var BaseResolver = class {
28141
28163
  return null;
28142
28164
  return this.validateDidDoc(did, got);
28143
28165
  }
28144
- async refreshCache(did) {
28145
- await this.cache?.refreshCache(did, () => this.resolveNoCache(did));
28166
+ async refreshCache(did, prevResult) {
28167
+ await this.cache?.refreshCache(did, () => this.resolveNoCache(did), prevResult);
28146
28168
  }
28147
28169
  async resolve(did, forceRefresh = false) {
28170
+ let fromCache = null;
28148
28171
  if (this.cache && !forceRefresh) {
28149
- const fromCache = await this.cache.checkCache(did);
28150
- if (fromCache?.stale) {
28151
- await this.refreshCache(did);
28152
- }
28153
- if (fromCache) {
28172
+ fromCache = await this.cache.checkCache(did);
28173
+ if (fromCache && !fromCache.expired) {
28174
+ if (fromCache?.stale) {
28175
+ await this.refreshCache(did, fromCache);
28176
+ }
28154
28177
  return fromCache.doc;
28155
28178
  }
28156
28179
  }
@@ -28159,7 +28182,7 @@ var BaseResolver = class {
28159
28182
  await this.cache?.clearEntry(did);
28160
28183
  return null;
28161
28184
  }
28162
- await this.cache?.cacheDid(did, got);
28185
+ await this.cache?.cacheDid(did, got, fromCache ?? void 0);
28163
28186
  return got;
28164
28187
  }
28165
28188
  async ensureResolve(did, forceRefresh = false) {
@@ -28177,8 +28200,8 @@ var BaseResolver = class {
28177
28200
  if (did.startsWith("did:key:")) {
28178
28201
  return did;
28179
28202
  } else {
28180
- const data = await this.resolveAtprotoData(did, forceRefresh);
28181
- return data.signingKey;
28203
+ const didDocument2 = await this.ensureResolve(did, forceRefresh);
28204
+ return ensureAtprotoKey(didDocument2);
28182
28205
  }
28183
28206
  }
28184
28207
  async verifySignature(did, data, sig, forceRefresh = false) {
@@ -28296,13 +28319,12 @@ var MemoryCache = class {
28296
28319
  return null;
28297
28320
  const now = Date.now();
28298
28321
  const expired = now > val.updatedAt + this.maxTTL;
28299
- if (expired)
28300
- return null;
28301
28322
  const stale = now > val.updatedAt + this.staleTTL;
28302
28323
  return {
28303
28324
  ...val,
28304
28325
  did,
28305
- stale
28326
+ stale,
28327
+ expired
28306
28328
  };
28307
28329
  }
28308
28330
  async clearEntry(did) {
@@ -28350,7 +28372,7 @@ var HandleResolver = class {
28350
28372
  const url = new URL("/.well-known/atproto-did", `https://${handle}`);
28351
28373
  try {
28352
28374
  const res = await fetch(url, { signal });
28353
- const did = await res.text();
28375
+ const did = (await res.text()).split("\n")[0].trim();
28354
28376
  if (typeof did === "string" && did.startsWith("did:")) {
28355
28377
  return did;
28356
28378
  }
@@ -28424,15 +28446,14 @@ var IdResolver = class {
28424
28446
  UnsupportedDidWebPathError,
28425
28447
  didDocument,
28426
28448
  ensureAtpDocument,
28449
+ ensureAtprotoKey,
28427
28450
  getDid,
28428
28451
  getFeedGen,
28429
28452
  getHandle,
28430
28453
  getKey,
28431
28454
  getNotif,
28432
28455
  getPds,
28433
- parseToAtprotoDocument,
28434
- service,
28435
- verificationMethod
28456
+ parseToAtprotoDocument
28436
28457
  });
28437
28458
  /*!
28438
28459
  * mime-db