@atproto/xrpc-server 0.3.3 → 0.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atproto/xrpc-server
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1801](https://github.com/bluesky-social/atproto/pull/1801) [`ce49743d`](https://github.com/bluesky-social/atproto/commit/ce49743d7f8800d33116b88001d7b512553c2c89) Thanks [@gaearon](https://github.com/gaearon)! - Methods that accepts lexicons now take `LexiconDoc` type instead of `unknown`
8
+
9
+ ### Patch Changes
10
+
11
+ - [#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"
12
+
13
+ - Updated dependencies [[`ce49743d`](https://github.com/bluesky-social/atproto/commit/ce49743d7f8800d33116b88001d7b512553c2c89), [`84e2d4d2`](https://github.com/bluesky-social/atproto/commit/84e2d4d2b6694f344d80c18672c78b650189d423)]:
14
+ - @atproto/lexicon@0.3.0
15
+ - @atproto/common@0.3.3
16
+ - @atproto/crypto@0.2.3
17
+
3
18
  ## 0.3.3
4
19
 
5
20
  ### 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
@@ -8,11 +8,11 @@ TypeScript library for implementing [atproto](https://atproto.com) HTTP API serv
8
8
  ## Usage
9
9
 
10
10
  ```typescript
11
+ import { LexiconDoc } from '@atproto/lexicon'
11
12
  import * as xrpc from '@atproto/xrpc-server'
12
13
  import express from 'express'
13
14
 
14
- // create xrpc server
15
- const server = xrpc.createServer([
15
+ const lexicons: LexiconDoc[] = [
16
16
  {
17
17
  lexicon: 1,
18
18
  id: 'io.example.ping',
@@ -29,7 +29,10 @@ const server = xrpc.createServer([
29
29
  },
30
30
  },
31
31
  },
32
- ])
32
+ ]
33
+
34
+ // create xrpc server
35
+ const server = xrpc.createServer(lexicons)
33
36
 
34
37
  function ping(ctx: {
35
38
  auth: xrpc.HandlerAuth | undefined
@@ -51,4 +54,9 @@ app.listen(8080)
51
54
 
52
55
  ## License
53
56
 
54
- MIT
57
+ This project is dual-licensed under MIT and Apache 2.0 terms:
58
+
59
+ - MIT license ([LICENSE-MIT.txt](https://github.com/bluesky-social/atproto/blob/main/LICENSE-MIT.txt) or http://opensource.org/licenses/MIT)
60
+ - 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)
61
+
62
+ 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/dist/auth.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import * as crypto from '@atproto/crypto';
2
- declare type ServiceJwtParams = {
2
+ declare type ServiceJwtPayload = {
3
3
  iss: string;
4
4
  aud: string;
5
5
  exp?: number;
6
+ };
7
+ declare type ServiceJwtParams = ServiceJwtPayload & {
6
8
  keypair: crypto.Keypair;
7
9
  };
8
10
  export declare const createServiceJwt: (params: ServiceJwtParams) => Promise<string>;
@@ -11,5 +13,5 @@ export declare const createServiceAuthHeaders: (params: ServiceJwtParams) => Pro
11
13
  authorization: string;
12
14
  };
13
15
  }>;
14
- export declare const verifyJwt: (jwtStr: string, ownDid: string | null, getSigningKey: (did: string) => Promise<string>) => Promise<string>;
16
+ export declare const verifyJwt: (jwtStr: string, ownDid: string | null, getSigningKey: (did: string, forceRefresh: boolean) => Promise<string>) => Promise<ServiceJwtPayload>;
15
17
  export {};
package/dist/index.js CHANGED
@@ -45773,15 +45773,6 @@ var discriminatedObject = z.object({ $type: z.string() });
45773
45773
  function isDiscriminatedObject(value) {
45774
45774
  return discriminatedObject.safeParse(value).success;
45775
45775
  }
45776
- var LexiconDocMalformedError = class extends Error {
45777
- constructor(message, schemaDef, issues) {
45778
- super(message);
45779
- this.schemaDef = schemaDef;
45780
- this.issues = issues;
45781
- this.schemaDef = schemaDef;
45782
- this.issues = issues;
45783
- }
45784
- };
45785
45776
  var ValidationError = class extends Error {
45786
45777
  };
45787
45778
  var InvalidLexiconError = class extends Error {
@@ -45862,23 +45853,13 @@ var Lexicons = class {
45862
45853
  }
45863
45854
  }
45864
45855
  add(doc) {
45865
- try {
45866
- lexiconDoc.parse(doc);
45867
- } catch (e) {
45868
- if (e instanceof ZodError) {
45869
- throw new LexiconDocMalformedError(`Failed to parse schema definition ${doc.id}`, doc, e.issues);
45870
- } else {
45871
- throw e;
45872
- }
45873
- }
45874
- const validatedDoc = doc;
45875
- const uri2 = toLexUri(validatedDoc.id);
45856
+ const uri2 = toLexUri(doc.id);
45876
45857
  if (this.docs.has(uri2)) {
45877
45858
  throw new Error(`${uri2} has already been registered`);
45878
45859
  }
45879
- resolveRefUris(validatedDoc, uri2);
45880
- this.docs.set(uri2, validatedDoc);
45881
- for (const [defUri, def2] of iterDefs(validatedDoc)) {
45860
+ resolveRefUris(doc, uri2);
45861
+ this.docs.set(uri2, doc);
45862
+ for (const [defUri, def2] of iterDefs(doc)) {
45882
45863
  this.defs.set(defUri, def2);
45883
45864
  }
45884
45865
  }
@@ -51936,16 +51917,18 @@ var decompressPubkey2 = (compressed) => {
51936
51917
  };
51937
51918
 
51938
51919
  // ../crypto/src/p256/operations.ts
51939
- var verifyDidSig = async (did2, data, sig) => {
51920
+ var verifyDidSig = async (did2, data, sig, opts) => {
51940
51921
  const { jwtAlg, keyBytes } = parseDidKey(did2);
51941
51922
  if (jwtAlg !== P256_JWT_ALG) {
51942
51923
  throw new Error(`Not a P-256 did:key: ${did2}`);
51943
51924
  }
51944
- return verifySig(keyBytes, data, sig);
51925
+ return verifySig(keyBytes, data, sig, opts);
51945
51926
  };
51946
- var verifySig = async (publicKey, data, sig) => {
51927
+ var verifySig = async (publicKey, data, sig, opts) => {
51947
51928
  const msgHash = await sha2562(data);
51948
- return p256.verify(sig, msgHash, publicKey, { lowS: true });
51929
+ return p256.verify(sig, msgHash, publicKey, {
51930
+ lowS: opts?.lowS ?? true
51931
+ });
51949
51932
  };
51950
51933
 
51951
51934
  // ../crypto/src/p256/plugin.ts
@@ -51957,16 +51940,18 @@ var p256Plugin = {
51957
51940
  var plugin_default = p256Plugin;
51958
51941
 
51959
51942
  // ../crypto/src/secp256k1/operations.ts
51960
- var verifyDidSig2 = async (did2, data, sig) => {
51943
+ var verifyDidSig2 = async (did2, data, sig, opts) => {
51961
51944
  const { jwtAlg, keyBytes } = parseDidKey(did2);
51962
51945
  if (jwtAlg !== SECP256K1_JWT_ALG) {
51963
51946
  throw new Error(`Not a secp256k1 did:key: ${did2}`);
51964
51947
  }
51965
- return verifySig2(keyBytes, data, sig);
51948
+ return verifySig2(keyBytes, data, sig, opts);
51966
51949
  };
51967
- var verifySig2 = async (publicKey, data, sig) => {
51950
+ var verifySig2 = async (publicKey, data, sig, opts) => {
51968
51951
  const msgHash = await sha2562(data);
51969
- return secp256k1.verify(sig, msgHash, publicKey, { lowS: true });
51952
+ return secp256k1.verify(sig, msgHash, publicKey, {
51953
+ lowS: opts?.lowS ?? true
51954
+ });
51970
51955
  };
51971
51956
 
51972
51957
  // ../crypto/src/secp256k1/plugin.ts
@@ -52013,13 +51998,13 @@ var hasPrefix = (bytes3, prefix) => {
52013
51998
  };
52014
51999
 
52015
52000
  // ../crypto/src/verify.ts
52016
- var verifySignature = (didKey, data, sig) => {
52001
+ var verifySignature = (didKey, data, sig, opts) => {
52017
52002
  const parsed = parseDidKey(didKey);
52018
52003
  const plugin = plugins_default.find((p) => p.jwtAlg === parsed.jwtAlg);
52019
52004
  if (!plugin) {
52020
- throw new Error(`Unsupported signature alg: :${parsed.jwtAlg}`);
52005
+ throw new Error(`Unsupported signature alg: ${parsed.jwtAlg}`);
52021
52006
  }
52022
- return plugin.verifySignature(didKey, data, sig);
52007
+ return plugin.verifySignature(didKey, data, sig, opts);
52023
52008
  };
52024
52009
 
52025
52010
  // src/auth.ts
@@ -52064,17 +52049,30 @@ var verifyJwt = async (jwtStr, ownDid, getSigningKey) => {
52064
52049
  }
52065
52050
  const msgBytes = fromString2(parts.slice(0, 2).join("."), "utf8");
52066
52051
  const sigBytes = fromString2(sig, "base64url");
52067
- const signingKey = await getSigningKey(payload.iss);
52052
+ const verifySignatureWithKey = (key) => {
52053
+ return verifySignature(key, msgBytes, sigBytes, {
52054
+ lowS: false
52055
+ });
52056
+ };
52057
+ const signingKey = await getSigningKey(payload.iss, false);
52068
52058
  let validSig;
52069
52059
  try {
52070
- validSig = await verifySignature(signingKey, msgBytes, sigBytes);
52060
+ validSig = await verifySignatureWithKey(signingKey);
52071
52061
  } catch (err) {
52072
52062
  throw new AuthRequiredError("could not verify jwt signature", "BadJwtSignature");
52073
52063
  }
52064
+ if (!validSig) {
52065
+ const freshSigningKey = await getSigningKey(payload.iss, true);
52066
+ try {
52067
+ validSig = freshSigningKey !== signingKey ? await verifySignatureWithKey(freshSigningKey) : false;
52068
+ } catch (err) {
52069
+ throw new AuthRequiredError("could not verify jwt signature", "BadJwtSignature");
52070
+ }
52071
+ }
52074
52072
  if (!validSig) {
52075
52073
  throw new AuthRequiredError("jwt signature does not match jwt issuer", "BadJwtSignature");
52076
52074
  }
52077
- return payload.iss;
52075
+ return payload;
52078
52076
  };
52079
52077
  var parseB64UrlToJson = (b64) => {
52080
52078
  return JSON.parse(b64UrlToUtf8(b64));