@atproto/pds 0.4.165 → 0.4.167
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 +20 -0
- package/dist/account-manager/account-manager.js +2 -2
- package/dist/account-manager/account-manager.js.map +1 -1
- package/dist/account-manager/helpers/account-device.d.ts +4 -4
- package/dist/account-manager/helpers/account.d.ts +1 -1
- package/dist/account-manager/helpers/auth.d.ts +1 -1
- package/dist/account-manager/helpers/auth.d.ts.map +1 -1
- package/dist/account-manager/helpers/auth.js +8 -8
- package/dist/account-manager/helpers/auth.js.map +1 -1
- package/dist/account-manager/helpers/authorization-request.d.ts +1 -1
- package/dist/account-manager/helpers/authorization-request.d.ts.map +1 -1
- package/dist/account-manager/helpers/authorization-request.js +16 -8
- package/dist/account-manager/helpers/authorization-request.js.map +1 -1
- package/dist/account-manager/helpers/token.d.ts +65 -65
- package/dist/actor-store/preference/reader.d.ts +2 -2
- package/dist/actor-store/preference/reader.d.ts.map +1 -1
- package/dist/actor-store/preference/reader.js +2 -2
- package/dist/actor-store/preference/reader.js.map +1 -1
- package/dist/actor-store/preference/transactor.d.ts +2 -2
- package/dist/actor-store/preference/transactor.d.ts.map +1 -1
- package/dist/actor-store/preference/transactor.js +5 -5
- package/dist/actor-store/preference/transactor.js.map +1 -1
- package/dist/actor-store/preference/util.d.ts +4 -2
- package/dist/actor-store/preference/util.d.ts.map +1 -1
- package/dist/actor-store/preference/util.js +9 -8
- package/dist/actor-store/preference/util.js.map +1 -1
- package/dist/actor-store/record/reader.d.ts +2 -2
- package/dist/api/app/bsky/actor/getPreferences.d.ts.map +1 -1
- package/dist/api/app/bsky/actor/getPreferences.js +29 -7
- package/dist/api/app/bsky/actor/getPreferences.js.map +1 -1
- package/dist/api/app/bsky/actor/getProfile.d.ts.map +1 -1
- package/dist/api/app/bsky/actor/getProfile.js +9 -1
- package/dist/api/app/bsky/actor/getProfile.js.map +1 -1
- package/dist/api/app/bsky/actor/getProfiles.d.ts.map +1 -1
- package/dist/api/app/bsky/actor/getProfiles.js +9 -1
- package/dist/api/app/bsky/actor/getProfiles.js.map +1 -1
- package/dist/api/app/bsky/actor/putPreferences.d.ts.map +1 -1
- package/dist/api/app/bsky/actor/putPreferences.js +30 -8
- package/dist/api/app/bsky/actor/putPreferences.js.map +1 -1
- package/dist/api/app/bsky/feed/getActorLikes.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getActorLikes.js +9 -1
- package/dist/api/app/bsky/feed/getActorLikes.js.map +1 -1
- package/dist/api/app/bsky/feed/getAuthorFeed.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getAuthorFeed.js +9 -1
- package/dist/api/app/bsky/feed/getAuthorFeed.js.map +1 -1
- package/dist/api/app/bsky/feed/getFeed.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getFeed.js +8 -1
- package/dist/api/app/bsky/feed/getFeed.js.map +1 -1
- package/dist/api/app/bsky/feed/getPostThread.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getPostThread.js +8 -1
- package/dist/api/app/bsky/feed/getPostThread.js.map +1 -1
- package/dist/api/app/bsky/feed/getTimeline.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getTimeline.js +9 -1
- package/dist/api/app/bsky/feed/getTimeline.js.map +1 -1
- package/dist/api/app/bsky/notification/registerPush.d.ts.map +1 -1
- package/dist/api/app/bsky/notification/registerPush.js +16 -4
- package/dist/api/app/bsky/notification/registerPush.js.map +1 -1
- package/dist/api/com/atproto/identity/getRecommendedDidCredentials.d.ts.map +1 -1
- package/dist/api/com/atproto/identity/getRecommendedDidCredentials.js +5 -1
- package/dist/api/com/atproto/identity/getRecommendedDidCredentials.js.map +1 -1
- package/dist/api/com/atproto/identity/requestPlcOperationSignature.d.ts.map +1 -1
- package/dist/api/com/atproto/identity/requestPlcOperationSignature.js +9 -2
- package/dist/api/com/atproto/identity/requestPlcOperationSignature.js.map +1 -1
- package/dist/api/com/atproto/identity/signPlcOperation.d.ts.map +1 -1
- package/dist/api/com/atproto/identity/signPlcOperation.js +9 -1
- package/dist/api/com/atproto/identity/signPlcOperation.js.map +1 -1
- package/dist/api/com/atproto/identity/submitPlcOperation.d.ts.map +1 -1
- package/dist/api/com/atproto/identity/submitPlcOperation.js +5 -1
- package/dist/api/com/atproto/identity/submitPlcOperation.js.map +1 -1
- package/dist/api/com/atproto/identity/updateHandle.d.ts.map +1 -1
- package/dist/api/com/atproto/identity/updateHandle.js +6 -1
- package/dist/api/com/atproto/identity/updateHandle.js.map +1 -1
- package/dist/api/com/atproto/moderation/createReport.d.ts.map +1 -1
- package/dist/api/com/atproto/moderation/createReport.js +8 -3
- package/dist/api/com/atproto/moderation/createReport.js.map +1 -1
- package/dist/api/com/atproto/repo/applyWrites.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/applyWrites.js +25 -19
- package/dist/api/com/atproto/repo/applyWrites.js.map +1 -1
- package/dist/api/com/atproto/repo/createRecord.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/createRecord.js +10 -1
- package/dist/api/com/atproto/repo/createRecord.js.map +1 -1
- package/dist/api/com/atproto/repo/deleteRecord.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/deleteRecord.js +12 -1
- package/dist/api/com/atproto/repo/deleteRecord.js.map +1 -1
- package/dist/api/com/atproto/repo/importRepo.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/importRepo.js +7 -2
- package/dist/api/com/atproto/repo/importRepo.js.map +1 -1
- package/dist/api/com/atproto/repo/listMissingBlobs.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/listMissingBlobs.js +6 -2
- package/dist/api/com/atproto/repo/listMissingBlobs.js.map +1 -1
- package/dist/api/com/atproto/repo/putRecord.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/putRecord.js +17 -11
- package/dist/api/com/atproto/repo/putRecord.js.map +1 -1
- package/dist/api/com/atproto/repo/uploadBlob.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/uploadBlob.js +5 -1
- package/dist/api/com/atproto/repo/uploadBlob.js.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.js +7 -1
- package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/checkAccountStatus.d.ts.map +1 -1
- package/dist/api/com/atproto/server/checkAccountStatus.js +5 -1
- package/dist/api/com/atproto/server/checkAccountStatus.js.map +1 -1
- package/dist/api/com/atproto/server/confirmEmail.d.ts.map +1 -1
- package/dist/api/com/atproto/server/confirmEmail.js +6 -1
- package/dist/api/com/atproto/server/confirmEmail.js.map +1 -1
- package/dist/api/com/atproto/server/createAppPassword.d.ts.map +1 -1
- package/dist/api/com/atproto/server/createAppPassword.js +7 -1
- package/dist/api/com/atproto/server/createAppPassword.js.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js +9 -2
- package/dist/api/com/atproto/server/deactivateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/deleteSession.d.ts.map +1 -1
- package/dist/api/com/atproto/server/deleteSession.js +3 -1
- package/dist/api/com/atproto/server/deleteSession.js.map +1 -1
- package/dist/api/com/atproto/server/getAccountInviteCodes.d.ts.map +1 -1
- package/dist/api/com/atproto/server/getAccountInviteCodes.js +8 -1
- package/dist/api/com/atproto/server/getAccountInviteCodes.js.map +1 -1
- package/dist/api/com/atproto/server/getServiceAuth.d.ts.map +1 -1
- package/dist/api/com/atproto/server/getServiceAuth.js +24 -13
- package/dist/api/com/atproto/server/getServiceAuth.js.map +1 -1
- package/dist/api/com/atproto/server/getSession.d.ts.map +1 -1
- package/dist/api/com/atproto/server/getSession.js +12 -19
- package/dist/api/com/atproto/server/getSession.js.map +1 -1
- package/dist/api/com/atproto/server/listAppPasswords.d.ts.map +1 -1
- package/dist/api/com/atproto/server/listAppPasswords.js +6 -1
- package/dist/api/com/atproto/server/listAppPasswords.js.map +1 -1
- package/dist/api/com/atproto/server/refreshSession.js +1 -1
- package/dist/api/com/atproto/server/refreshSession.js.map +1 -1
- package/dist/api/com/atproto/server/requestAccountDelete.d.ts.map +1 -1
- package/dist/api/com/atproto/server/requestAccountDelete.js +8 -1
- package/dist/api/com/atproto/server/requestAccountDelete.js.map +1 -1
- package/dist/api/com/atproto/server/requestEmailConfirmation.d.ts.map +1 -1
- package/dist/api/com/atproto/server/requestEmailConfirmation.js +6 -1
- package/dist/api/com/atproto/server/requestEmailConfirmation.js.map +1 -1
- package/dist/api/com/atproto/server/requestEmailUpdate.d.ts.map +1 -1
- package/dist/api/com/atproto/server/requestEmailUpdate.js +6 -1
- package/dist/api/com/atproto/server/requestEmailUpdate.js.map +1 -1
- package/dist/api/com/atproto/server/revokeAppPassword.d.ts.map +1 -1
- package/dist/api/com/atproto/server/revokeAppPassword.js +6 -1
- package/dist/api/com/atproto/server/revokeAppPassword.js.map +1 -1
- package/dist/api/com/atproto/server/updateEmail.d.ts.map +1 -1
- package/dist/api/com/atproto/server/updateEmail.js +8 -1
- package/dist/api/com/atproto/server/updateEmail.js.map +1 -1
- package/dist/api/com/atproto/sync/deprecated/getCheckout.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/deprecated/getCheckout.js +7 -2
- package/dist/api/com/atproto/sync/deprecated/getCheckout.js.map +1 -1
- package/dist/api/com/atproto/sync/deprecated/getHead.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/deprecated/getHead.js +7 -2
- package/dist/api/com/atproto/sync/deprecated/getHead.js.map +1 -1
- package/dist/api/com/atproto/sync/getBlob.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/getBlob.js +7 -3
- package/dist/api/com/atproto/sync/getBlob.js.map +1 -1
- package/dist/api/com/atproto/sync/getBlocks.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/getBlocks.js +7 -2
- package/dist/api/com/atproto/sync/getBlocks.js.map +1 -1
- package/dist/api/com/atproto/sync/getLatestCommit.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/getLatestCommit.js +7 -2
- package/dist/api/com/atproto/sync/getLatestCommit.js.map +1 -1
- package/dist/api/com/atproto/sync/getRecord.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/getRecord.js +7 -2
- package/dist/api/com/atproto/sync/getRecord.js.map +1 -1
- package/dist/api/com/atproto/sync/getRepo.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/getRepo.js +7 -3
- package/dist/api/com/atproto/sync/getRepo.js.map +1 -1
- package/dist/api/com/atproto/sync/listBlobs.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/listBlobs.js +7 -3
- package/dist/api/com/atproto/sync/listBlobs.js.map +1 -1
- package/dist/api/com/atproto/temp/checkSignupQueue.d.ts.map +1 -1
- package/dist/api/com/atproto/temp/checkSignupQueue.js +7 -3
- package/dist/api/com/atproto/temp/checkSignupQueue.js.map +1 -1
- package/dist/auth-output.d.ts +45 -0
- package/dist/auth-output.d.ts.map +1 -0
- package/dist/auth-output.js +3 -0
- package/dist/auth-output.js.map +1 -0
- package/dist/auth-scope.d.ts +16 -0
- package/dist/auth-scope.d.ts.map +1 -0
- package/dist/auth-scope.js +40 -0
- package/dist/auth-scope.js.map +1 -0
- package/dist/auth-verifier.d.ts +50 -115
- package/dist/auth-verifier.d.ts.map +1 -1
- package/dist/auth-verifier.js +275 -366
- package/dist/auth-verifier.js.map +1 -1
- package/dist/config/config.d.ts +2 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +2 -1
- package/dist/config/config.js.map +1 -1
- package/dist/config/env.d.ts +1 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +3 -1
- package/dist/config/env.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +5 -5
- package/dist/context.js.map +1 -1
- package/dist/lexicon/index.d.ts +230 -230
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +687 -687
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +16650 -16650
- package/dist/lexicon/lexicons.js +9267 -9267
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/pipethrough.d.ts +5 -3
- package/dist/pipethrough.d.ts.map +1 -1
- package/dist/pipethrough.js +42 -15
- package/dist/pipethrough.js.map +1 -1
- package/dist/sequencer/events.d.ts +13 -13
- package/dist/util/http.d.ts +7 -0
- package/dist/util/http.d.ts.map +1 -0
- package/dist/util/http.js +31 -0
- package/dist/util/http.js.map +1 -0
- package/dist/util/types.d.ts +5 -0
- package/dist/util/types.d.ts.map +1 -0
- package/dist/util/types.js +3 -0
- package/dist/util/types.js.map +1 -0
- package/package.json +4 -3
- package/src/account-manager/account-manager.ts +1 -1
- package/src/account-manager/helpers/auth.ts +1 -1
- package/src/account-manager/helpers/authorization-request.ts +8 -4
- package/src/actor-store/preference/reader.ts +3 -4
- package/src/actor-store/preference/transactor.ts +6 -7
- package/src/actor-store/preference/util.ts +15 -5
- package/src/api/app/bsky/actor/getPreferences.ts +33 -8
- package/src/api/app/bsky/actor/getProfile.ts +9 -1
- package/src/api/app/bsky/actor/getProfiles.ts +9 -1
- package/src/api/app/bsky/actor/putPreferences.ts +35 -12
- package/src/api/app/bsky/feed/getActorLikes.ts +9 -1
- package/src/api/app/bsky/feed/getAuthorFeed.ts +9 -1
- package/src/api/app/bsky/feed/getFeed.ts +9 -2
- package/src/api/app/bsky/feed/getPostThread.ts +8 -1
- package/src/api/app/bsky/feed/getTimeline.ts +9 -1
- package/src/api/app/bsky/notification/registerPush.ts +16 -5
- package/src/api/com/atproto/identity/getRecommendedDidCredentials.ts +5 -1
- package/src/api/com/atproto/identity/requestPlcOperationSignature.ts +9 -2
- package/src/api/com/atproto/identity/signPlcOperation.ts +9 -1
- package/src/api/com/atproto/identity/submitPlcOperation.ts +5 -1
- package/src/api/com/atproto/identity/updateHandle.ts +6 -1
- package/src/api/com/atproto/moderation/createReport.ts +8 -3
- package/src/api/com/atproto/repo/applyWrites.ts +28 -20
- package/src/api/com/atproto/repo/createRecord.ts +12 -1
- package/src/api/com/atproto/repo/deleteRecord.ts +14 -1
- package/src/api/com/atproto/repo/importRepo.ts +9 -2
- package/src/api/com/atproto/repo/listMissingBlobs.ts +7 -2
- package/src/api/com/atproto/repo/putRecord.ts +18 -10
- package/src/api/com/atproto/repo/uploadBlob.ts +6 -2
- package/src/api/com/atproto/server/activateAccount.ts +10 -2
- package/src/api/com/atproto/server/checkAccountStatus.ts +5 -1
- package/src/api/com/atproto/server/confirmEmail.ts +6 -1
- package/src/api/com/atproto/server/createAppPassword.ts +9 -1
- package/src/api/com/atproto/server/deactivateAccount.ts +11 -2
- package/src/api/com/atproto/server/deleteSession.ts +3 -1
- package/src/api/com/atproto/server/getAccountInviteCodes.ts +11 -2
- package/src/api/com/atproto/server/getServiceAuth.ts +37 -18
- package/src/api/com/atproto/server/getSession.ts +20 -27
- package/src/api/com/atproto/server/listAppPasswords.ts +8 -1
- package/src/api/com/atproto/server/refreshSession.ts +1 -1
- package/src/api/com/atproto/server/requestAccountDelete.ts +11 -2
- package/src/api/com/atproto/server/requestEmailConfirmation.ts +6 -1
- package/src/api/com/atproto/server/requestEmailUpdate.ts +6 -1
- package/src/api/com/atproto/server/revokeAppPassword.ts +8 -1
- package/src/api/com/atproto/server/updateEmail.ts +11 -2
- package/src/api/com/atproto/sync/deprecated/getCheckout.ts +7 -6
- package/src/api/com/atproto/sync/deprecated/getHead.ts +7 -6
- package/src/api/com/atproto/sync/getBlob.ts +7 -7
- package/src/api/com/atproto/sync/getBlocks.ts +7 -6
- package/src/api/com/atproto/sync/getLatestCommit.ts +7 -6
- package/src/api/com/atproto/sync/getRecord.ts +7 -6
- package/src/api/com/atproto/sync/getRepo.ts +7 -7
- package/src/api/com/atproto/sync/listBlobs.ts +7 -7
- package/src/api/com/atproto/temp/checkSignupQueue.ts +8 -2
- package/src/auth-output.ts +51 -0
- package/src/auth-scope.ts +40 -0
- package/src/auth-verifier.ts +404 -520
- package/src/config/config.ts +7 -7
- package/src/config/env.ts +5 -1
- package/src/context.ts +6 -5
- package/src/lexicon/index.ts +1235 -1235
- package/src/lexicon/lexicons.ts +9416 -9416
- package/src/pipethrough.ts +61 -18
- package/src/util/http.ts +31 -0
- package/src/util/types.ts +7 -0
- package/tests/oauth.test.ts +11 -37
- package/tests/preferences.test.ts +7 -3
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/auth-verifier.js
CHANGED
@@ -36,32 +36,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
37
37
|
};
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
39
|
-
exports.createPublicKeyObject = exports.createSecretKeyObject = exports.
|
39
|
+
exports.createPublicKeyObject = exports.createSecretKeyObject = exports.AuthVerifier = void 0;
|
40
|
+
exports.isUserOrAdmin = isUserOrAdmin;
|
40
41
|
const node_crypto_1 = require("node:crypto");
|
41
42
|
const jose = __importStar(require("jose"));
|
42
43
|
const key_encoder_1 = __importDefault(require("key-encoder"));
|
43
44
|
const common_1 = require("@atproto/common");
|
44
45
|
const identity_1 = require("@atproto/identity");
|
45
46
|
const oauth_provider_1 = require("@atproto/oauth-provider");
|
47
|
+
const oauth_scopes_1 = require("@atproto/oauth-scopes");
|
46
48
|
const xrpc_server_1 = require("@atproto/xrpc-server");
|
49
|
+
const auth_scope_1 = require("./auth-scope");
|
47
50
|
const db_1 = require("./db");
|
48
51
|
const logger_1 = require("./logger");
|
49
|
-
|
50
|
-
var AuthScope;
|
51
|
-
(function (AuthScope) {
|
52
|
-
AuthScope["Access"] = "com.atproto.access";
|
53
|
-
AuthScope["Refresh"] = "com.atproto.refresh";
|
54
|
-
AuthScope["AppPass"] = "com.atproto.appPass";
|
55
|
-
AuthScope["AppPassPrivileged"] = "com.atproto.appPassPrivileged";
|
56
|
-
AuthScope["SignupQueued"] = "com.atproto.signupQueued";
|
57
|
-
AuthScope["Takendown"] = "com.atproto.takendown";
|
58
|
-
})(AuthScope || (exports.AuthScope = AuthScope = {}));
|
59
|
-
var RoleStatus;
|
60
|
-
(function (RoleStatus) {
|
61
|
-
RoleStatus[RoleStatus["Valid"] = 0] = "Valid";
|
62
|
-
RoleStatus[RoleStatus["Invalid"] = 1] = "Invalid";
|
63
|
-
RoleStatus[RoleStatus["Missing"] = 2] = "Missing";
|
64
|
-
})(RoleStatus || (exports.RoleStatus = RoleStatus = {}));
|
52
|
+
const http_1 = require("./util/http");
|
65
53
|
class AuthVerifier {
|
66
54
|
constructor(accountManager, idResolver, oauthVerifier, opts) {
|
67
55
|
Object.defineProperty(this, "accountManager", {
|
@@ -107,70 +95,21 @@ class AuthVerifier {
|
|
107
95
|
value: void 0
|
108
96
|
});
|
109
97
|
// verifiers (arrow fns to preserve scope)
|
110
|
-
Object.defineProperty(this, "
|
98
|
+
Object.defineProperty(this, "unauthenticated", {
|
111
99
|
enumerable: true,
|
112
100
|
configurable: true,
|
113
101
|
writable: true,
|
114
|
-
value: (
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
]
|
121
|
-
|
122
|
-
|
123
|
-
Object.defineProperty(this, "accessFull", {
|
124
|
-
enumerable: true,
|
125
|
-
configurable: true,
|
126
|
-
writable: true,
|
127
|
-
value: (opts = {}) => (ctx) => {
|
128
|
-
return this.validateAccessToken(ctx, [AuthScope.Access, ...(opts.additional ?? [])], opts);
|
129
|
-
}
|
130
|
-
});
|
131
|
-
Object.defineProperty(this, "accessPrivileged", {
|
132
|
-
enumerable: true,
|
133
|
-
configurable: true,
|
134
|
-
writable: true,
|
135
|
-
value: (opts = {}) => (ctx) => {
|
136
|
-
return this.validateAccessToken(ctx, [
|
137
|
-
AuthScope.Access,
|
138
|
-
AuthScope.AppPassPrivileged,
|
139
|
-
...(opts.additional ?? []),
|
140
|
-
]);
|
141
|
-
}
|
142
|
-
});
|
143
|
-
Object.defineProperty(this, "refresh", {
|
144
|
-
enumerable: true,
|
145
|
-
configurable: true,
|
146
|
-
writable: true,
|
147
|
-
value: async (ctx) => {
|
148
|
-
const { did, scope, tokenId } = await this.validateRefreshToken(ctx);
|
149
|
-
return {
|
150
|
-
credentials: {
|
151
|
-
type: 'refresh',
|
152
|
-
did,
|
153
|
-
scope,
|
154
|
-
tokenId,
|
155
|
-
},
|
156
|
-
};
|
157
|
-
}
|
158
|
-
});
|
159
|
-
Object.defineProperty(this, "refreshExpired", {
|
160
|
-
enumerable: true,
|
161
|
-
configurable: true,
|
162
|
-
writable: true,
|
163
|
-
value: async (ctx) => {
|
164
|
-
const { did, scope, tokenId } = await this.validateRefreshToken(ctx, {
|
165
|
-
clockTolerance: Infinity,
|
166
|
-
});
|
102
|
+
value: (ctx) => {
|
103
|
+
setAuthHeaders(ctx.res);
|
104
|
+
// @NOTE this auth method is typically used as fallback when no other auth
|
105
|
+
// method is applicable. This means that the presence of an "authorization"
|
106
|
+
// header means that that header is invalid (as it did not match any of the
|
107
|
+
// other auth methods).
|
108
|
+
if (ctx.req.headers['authorization']) {
|
109
|
+
throw new xrpc_server_1.AuthRequiredError('Invalid authorization header');
|
110
|
+
}
|
167
111
|
return {
|
168
|
-
credentials:
|
169
|
-
type: 'refresh',
|
170
|
-
did,
|
171
|
-
scope,
|
172
|
-
tokenId,
|
173
|
-
},
|
112
|
+
credentials: null,
|
174
113
|
};
|
175
114
|
}
|
176
115
|
});
|
@@ -179,111 +118,78 @@ class AuthVerifier {
|
|
179
118
|
configurable: true,
|
180
119
|
writable: true,
|
181
120
|
value: async (ctx) => {
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
Object.defineProperty(this, "optionalAccessOrAdminToken", {
|
187
|
-
enumerable: true,
|
188
|
-
configurable: true,
|
189
|
-
writable: true,
|
190
|
-
value: (opts = {}) => async (ctx) => {
|
191
|
-
if (isAccessToken(ctx.req)) {
|
192
|
-
return await this.accessStandard(opts)(ctx);
|
121
|
+
setAuthHeaders(ctx.res);
|
122
|
+
const parsed = parseBasicAuth(ctx.req);
|
123
|
+
if (!parsed) {
|
124
|
+
throw new xrpc_server_1.AuthRequiredError();
|
193
125
|
}
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
else {
|
198
|
-
return this.null(ctx);
|
126
|
+
const { username, password } = parsed;
|
127
|
+
if (username !== 'admin' || password !== this._adminPass) {
|
128
|
+
throw new xrpc_server_1.AuthRequiredError();
|
199
129
|
}
|
130
|
+
return { credentials: { type: 'admin_token' } };
|
200
131
|
}
|
201
132
|
});
|
202
|
-
Object.defineProperty(this, "
|
133
|
+
Object.defineProperty(this, "modService", {
|
203
134
|
enumerable: true,
|
204
135
|
configurable: true,
|
205
136
|
writable: true,
|
206
137
|
value: async (ctx) => {
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
});
|
211
|
-
if (payload.aud !== this.dids.pds &&
|
212
|
-
(!this.dids.entryway || payload.aud !== this.dids.entryway)) {
|
213
|
-
throw new xrpc_server_1.AuthRequiredError('jwt audience does not match service did', 'BadJwtAudience');
|
138
|
+
setAuthHeaders(ctx.res);
|
139
|
+
if (!this.dids.modService) {
|
140
|
+
throw new xrpc_server_1.AuthRequiredError('Untrusted issuer', 'UntrustedIss');
|
214
141
|
}
|
142
|
+
const payload = await this.verifyServiceJwt(ctx.req, {
|
143
|
+
iss: [this.dids.modService, `${this.dids.modService}#atproto_labeler`],
|
144
|
+
});
|
215
145
|
return {
|
216
146
|
credentials: {
|
217
|
-
type: '
|
218
|
-
aud: payload.aud,
|
147
|
+
type: 'mod_service',
|
219
148
|
did: payload.iss,
|
220
149
|
},
|
221
150
|
};
|
222
151
|
}
|
223
152
|
});
|
224
|
-
Object.defineProperty(this, "
|
153
|
+
Object.defineProperty(this, "moderator", {
|
225
154
|
enumerable: true,
|
226
155
|
configurable: true,
|
227
156
|
writable: true,
|
228
157
|
value: async (ctx) => {
|
229
|
-
|
230
|
-
|
158
|
+
const type = extractAuthType(ctx.req);
|
159
|
+
if (type === AuthType.BEARER) {
|
160
|
+
return this.modService(ctx);
|
231
161
|
}
|
232
162
|
else {
|
233
|
-
return this.
|
234
|
-
}
|
235
|
-
}
|
236
|
-
});
|
237
|
-
Object.defineProperty(this, "accessOrUserServiceAuth", {
|
238
|
-
enumerable: true,
|
239
|
-
configurable: true,
|
240
|
-
writable: true,
|
241
|
-
value: (opts = {}) => async (ctx) => {
|
242
|
-
const token = bearerTokenFromReq(ctx.req);
|
243
|
-
if (token) {
|
244
|
-
const payload = jose.decodeJwt(token);
|
245
|
-
if (payload['lxm']) {
|
246
|
-
return this.userServiceAuth(ctx);
|
247
|
-
}
|
163
|
+
return this.adminToken(ctx);
|
248
164
|
}
|
249
|
-
return this.accessStandard(opts)(ctx);
|
250
165
|
}
|
251
166
|
});
|
252
|
-
Object.defineProperty(this, "
|
167
|
+
Object.defineProperty(this, "userServiceAuth", {
|
253
168
|
enumerable: true,
|
254
169
|
configurable: true,
|
255
170
|
writable: true,
|
256
171
|
value: async (ctx) => {
|
257
|
-
|
258
|
-
|
259
|
-
}
|
260
|
-
const payload = await this.verifyServiceJwt(ctx, {
|
261
|
-
aud: null,
|
262
|
-
iss: [this.dids.modService, `${this.dids.modService}#atproto_labeler`],
|
263
|
-
});
|
264
|
-
if (payload.aud !== this.dids.pds &&
|
265
|
-
(!this.dids.entryway || payload.aud !== this.dids.entryway)) {
|
266
|
-
throw new xrpc_server_1.AuthRequiredError('jwt audience does not match service did', 'BadJwtAudience');
|
267
|
-
}
|
172
|
+
setAuthHeaders(ctx.res);
|
173
|
+
const payload = await this.verifyServiceJwt(ctx.req);
|
268
174
|
return {
|
269
175
|
credentials: {
|
270
|
-
type: '
|
271
|
-
|
272
|
-
iss: payload.iss,
|
176
|
+
type: 'user_service_auth',
|
177
|
+
did: payload.iss,
|
273
178
|
},
|
274
179
|
};
|
275
180
|
}
|
276
181
|
});
|
277
|
-
Object.defineProperty(this, "
|
182
|
+
Object.defineProperty(this, "userServiceAuthOptional", {
|
278
183
|
enumerable: true,
|
279
184
|
configurable: true,
|
280
185
|
writable: true,
|
281
186
|
value: async (ctx) => {
|
282
|
-
|
283
|
-
|
187
|
+
const type = extractAuthType(ctx.req);
|
188
|
+
if (type === AuthType.BEARER) {
|
189
|
+
return await this.userServiceAuth(ctx);
|
284
190
|
}
|
285
191
|
else {
|
286
|
-
return this.
|
192
|
+
return this.unauthenticated(ctx);
|
287
193
|
}
|
288
194
|
}
|
289
195
|
});
|
@@ -292,132 +198,131 @@ class AuthVerifier {
|
|
292
198
|
this._adminPass = opts.adminPass;
|
293
199
|
this.dids = opts.dids;
|
294
200
|
}
|
295
|
-
|
296
|
-
const
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
201
|
+
access(options) {
|
202
|
+
const { scopes, ...statusOptions } = options;
|
203
|
+
const verifyJwtOptions = {
|
204
|
+
audience: this.dids.pds,
|
205
|
+
typ: 'at+jwt',
|
206
|
+
scopes:
|
207
|
+
// @NOTE We can reject taken down credentials based on the scope if
|
208
|
+
// "checkTakedown" is set.
|
209
|
+
statusOptions.checkTakedown && scopes.includes(auth_scope_1.AuthScope.Takendown)
|
210
|
+
? scopes.filter((s) => s !== auth_scope_1.AuthScope.Takendown)
|
211
|
+
: scopes,
|
212
|
+
};
|
213
|
+
return async (ctx) => {
|
214
|
+
setAuthHeaders(ctx.res);
|
215
|
+
const { sub: did, scope } = await this.verifyBearerJwt(ctx.req, verifyJwtOptions);
|
216
|
+
await this.verifyStatus(did, statusOptions);
|
217
|
+
return {
|
218
|
+
credentials: { type: 'access', did, scope },
|
219
|
+
};
|
220
|
+
};
|
305
221
|
}
|
306
|
-
|
307
|
-
const
|
308
|
-
|
222
|
+
refresh(options) {
|
223
|
+
const verifyOptions = {
|
224
|
+
clockTolerance: options?.allowExpired ? Infinity : undefined,
|
309
225
|
typ: 'refresh+jwt',
|
310
226
|
// when using entryway, proxying refresh credentials
|
311
227
|
audience: this.dids.entryway ? this.dids.entryway : this.dids.pds,
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
228
|
+
scopes: [auth_scope_1.AuthScope.Refresh],
|
229
|
+
};
|
230
|
+
return async (ctx) => {
|
231
|
+
setAuthHeaders(ctx.res);
|
232
|
+
const result = await this.verifyBearerJwt(ctx.req, verifyOptions);
|
233
|
+
const tokenId = result.jti;
|
234
|
+
if (!tokenId) {
|
235
|
+
throw new xrpc_server_1.AuthRequiredError('Unexpected missing refresh token id', 'MissingTokenId');
|
236
|
+
}
|
237
|
+
return {
|
238
|
+
credentials: {
|
239
|
+
type: 'refresh',
|
240
|
+
did: result.sub,
|
241
|
+
scope: result.scope,
|
242
|
+
tokenId,
|
243
|
+
},
|
244
|
+
};
|
245
|
+
};
|
318
246
|
}
|
319
|
-
|
320
|
-
this.
|
321
|
-
|
322
|
-
|
323
|
-
throw new xrpc_server_1.AuthRequiredError(undefined, 'AuthMissing');
|
324
|
-
}
|
325
|
-
const { payload, protectedHeader } = await this.jwtVerify(token,
|
326
|
-
// @TODO: Once all access & refresh tokens have a "typ" claim (i.e. 90
|
327
|
-
// days after this code was deployed), replace the following line with
|
328
|
-
// "verifyOptions," (to re-enable the verification of the "typ" property
|
329
|
-
// from verifyJwt()). Once the change is made, the "if" block below that
|
330
|
-
// checks for "typ" can be removed.
|
331
|
-
{
|
332
|
-
...verifyOptions,
|
333
|
-
typ: undefined,
|
247
|
+
authorization({ scopes = auth_scope_1.ACCESS_STANDARD, additional = [], ...options }) {
|
248
|
+
const access = this.access({
|
249
|
+
...options,
|
250
|
+
scopes: [...scopes, ...additional],
|
334
251
|
});
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
352
|
-
}
|
353
|
-
if (payload['cnf'] !== undefined) {
|
354
|
-
// Proof-of-Possession (PoP) tokens are not allowed here
|
355
|
-
// https://www.rfc-editor.org/rfc/rfc7800.html
|
356
|
-
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
357
|
-
}
|
358
|
-
if (!isAuthScope(scope) || (scopes.length > 0 && !scopes.includes(scope))) {
|
359
|
-
throw new xrpc_server_1.InvalidRequestError('Bad token scope', 'InvalidToken');
|
360
|
-
}
|
361
|
-
return {
|
362
|
-
did: sub,
|
363
|
-
scope,
|
364
|
-
audience: aud,
|
365
|
-
token,
|
366
|
-
payload,
|
252
|
+
const oauth = this.oauth(options);
|
253
|
+
return async (ctx) => {
|
254
|
+
const type = extractAuthType(ctx.req);
|
255
|
+
if (type === AuthType.BEARER) {
|
256
|
+
return access(ctx);
|
257
|
+
}
|
258
|
+
if (type === AuthType.DPOP) {
|
259
|
+
return oauth(ctx);
|
260
|
+
}
|
261
|
+
// Auth headers are set through the access and oauth methods so we only
|
262
|
+
// need to set them here if we reach this point
|
263
|
+
setAuthHeaders(ctx.res);
|
264
|
+
if (type !== null) {
|
265
|
+
throw new xrpc_server_1.InvalidRequestError('Unexpected authorization type', 'InvalidToken');
|
266
|
+
}
|
267
|
+
throw new xrpc_server_1.AuthRequiredError(undefined, 'AuthMissing');
|
367
268
|
};
|
368
269
|
}
|
369
|
-
|
370
|
-
this.
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
accessOutput = await this.validateBearerAccessToken(ctx, scopes);
|
376
|
-
break;
|
270
|
+
authorizationOrAdminTokenOptional(opts) {
|
271
|
+
const authorization = this.authorization(opts);
|
272
|
+
return async (ctx) => {
|
273
|
+
const type = extractAuthType(ctx.req);
|
274
|
+
if (type === AuthType.BEARER || type === AuthType.DPOP) {
|
275
|
+
return authorization(ctx);
|
377
276
|
}
|
378
|
-
|
379
|
-
|
380
|
-
break;
|
277
|
+
else if (type === AuthType.BASIC) {
|
278
|
+
return this.adminToken(ctx);
|
381
279
|
}
|
382
|
-
|
383
|
-
|
384
|
-
default:
|
385
|
-
throw new xrpc_server_1.InvalidRequestError('Unexpected authorization type', 'InvalidToken');
|
386
|
-
}
|
387
|
-
if (checkTakedown || checkDeactivated) {
|
388
|
-
const found = await this.accountManager.getAccount(accessOutput.credentials.did, {
|
389
|
-
includeDeactivated: true,
|
390
|
-
includeTakenDown: true,
|
391
|
-
});
|
392
|
-
if (!found) {
|
393
|
-
// will be turned into ExpiredToken for the client if proxied by entryway
|
394
|
-
throw new xrpc_server_1.ForbiddenError('Account not found', 'AccountNotFound');
|
280
|
+
else {
|
281
|
+
return this.unauthenticated(ctx);
|
395
282
|
}
|
396
|
-
|
397
|
-
|
283
|
+
};
|
284
|
+
}
|
285
|
+
authorizationOrUserServiceAuth(options) {
|
286
|
+
const authorizationVerifier = this.authorization(options);
|
287
|
+
return async (ctx) => {
|
288
|
+
if (isDefinitelyServiceAuth(ctx.req)) {
|
289
|
+
return this.userServiceAuth(ctx);
|
398
290
|
}
|
399
|
-
|
400
|
-
|
291
|
+
else {
|
292
|
+
return authorizationVerifier(ctx);
|
401
293
|
}
|
402
|
-
}
|
403
|
-
return accessOutput;
|
294
|
+
};
|
404
295
|
}
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
296
|
+
oauth({ authorize, ...verifyStatusOptions }) {
|
297
|
+
const verifyTokenOptions = {
|
298
|
+
audience: [this.dids.pds],
|
299
|
+
scope: ['atproto'],
|
300
|
+
};
|
301
|
+
return async (ctx) => {
|
302
|
+
setAuthHeaders(ctx.res);
|
303
|
+
const { req, res } = ctx;
|
304
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-8.2
|
411
305
|
const dpopNonce = this.oauthVerifier.nextDpopNonce();
|
412
306
|
if (dpopNonce) {
|
413
307
|
res.setHeader('DPoP-Nonce', dpopNonce);
|
414
308
|
res.appendHeader('Access-Control-Expose-Headers', 'DPoP-Nonce');
|
415
309
|
}
|
416
|
-
|
417
|
-
try {
|
418
|
-
const originalUrl = ('originalUrl' in req && req.originalUrl) || req.url || '/';
|
310
|
+
const originalUrl = req.originalUrl || req.url || '/';
|
419
311
|
const url = new URL(originalUrl, this._publicUrl);
|
420
|
-
const { tokenClaims, dpopProof } = await this.oauthVerifier
|
312
|
+
const { tokenClaims, dpopProof } = await this.oauthVerifier
|
313
|
+
.authenticateRequest(req.method || 'GET', url, req.headers, verifyTokenOptions)
|
314
|
+
.catch((err) => {
|
315
|
+
// Make sure to include any WWW-Authenticate header in the response
|
316
|
+
// (particularly useful for DPoP's "use_dpop_nonce" error)
|
317
|
+
if (err instanceof oauth_provider_1.WWWAuthenticateError) {
|
318
|
+
res.setHeader('WWW-Authenticate', err.wwwAuthenticateHeader);
|
319
|
+
res.appendHeader('Access-Control-Expose-Headers', 'WWW-Authenticate');
|
320
|
+
}
|
321
|
+
if (err instanceof oauth_provider_1.OAuthError) {
|
322
|
+
throw new xrpc_server_1.XRPCError(err.status, err.error_description, err.error);
|
323
|
+
}
|
324
|
+
throw err;
|
325
|
+
});
|
421
326
|
// @TODO drop this once oauth provider no longer accepts DPoP proof with
|
422
327
|
// query or fragment in "htu" claim.
|
423
328
|
if (dpopProof?.htu.match(/[?#]/)) {
|
@@ -426,68 +331,103 @@ class AuthVerifier {
|
|
426
331
|
htu: dpopProof.htu,
|
427
332
|
}, 'DPoP proof "htu" contains query or fragment');
|
428
333
|
}
|
429
|
-
const { sub } = tokenClaims;
|
430
|
-
if (typeof
|
334
|
+
const { sub: did } = tokenClaims;
|
335
|
+
if (typeof did !== 'string' || !did.startsWith('did:')) {
|
431
336
|
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
432
337
|
}
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
? AuthScope.AppPassPrivileged
|
439
|
-
: AuthScope.AppPass;
|
440
|
-
if (!scopes.includes(scopeEquivalent)) {
|
441
|
-
// AppPassPrivileged is sufficient but was not provided "transition:chat.bsky"
|
442
|
-
if (scopes.includes(AuthScope.AppPassPrivileged)) {
|
443
|
-
throw new xrpc_server_1.InvalidRequestError('Missing required scope: transition:chat.bsky', 'InvalidToken');
|
444
|
-
}
|
445
|
-
// AuthScope.Access and AuthScope.SignupQueued do not have an OAuth
|
446
|
-
// scope equivalent.
|
447
|
-
throw new xrpc_server_1.InvalidRequestError('DPoP access token cannot be used for this request', 'InvalidToken');
|
338
|
+
await this.verifyStatus(did, verifyStatusOptions);
|
339
|
+
const permissions = new oauth_scopes_1.PermissionSetTransition(tokenClaims.scope?.split(' '));
|
340
|
+
// Should never happen
|
341
|
+
if (!permissions.scopes.has('atproto')) {
|
342
|
+
throw new xrpc_server_1.InvalidRequestError('OAuth token does not have "atproto" scope', 'InvalidToken');
|
448
343
|
}
|
344
|
+
await authorize(permissions, ctx);
|
449
345
|
return {
|
450
346
|
credentials: {
|
451
347
|
type: 'oauth',
|
452
|
-
did
|
453
|
-
|
454
|
-
oauthScopes,
|
455
|
-
isPrivileged: scopeEquivalent === AuthScope.AppPassPrivileged,
|
348
|
+
did,
|
349
|
+
permissions,
|
456
350
|
},
|
457
351
|
};
|
458
|
-
}
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
352
|
+
};
|
353
|
+
}
|
354
|
+
async verifyStatus(did, { checkTakedown = false, checkDeactivated = false }) {
|
355
|
+
if (checkTakedown || checkDeactivated) {
|
356
|
+
const found = await this.accountManager.getAccount(did, {
|
357
|
+
includeDeactivated: true,
|
358
|
+
includeTakenDown: true,
|
359
|
+
});
|
360
|
+
if (!found) {
|
361
|
+
// will be turned into ExpiredToken for the client if proxied by entryway
|
362
|
+
throw new xrpc_server_1.ForbiddenError('Account not found', 'AccountNotFound');
|
363
|
+
}
|
364
|
+
if (checkTakedown && (0, db_1.softDeleted)(found)) {
|
365
|
+
throw new xrpc_server_1.AuthRequiredError('Account has been taken down', 'AccountTakedown');
|
465
366
|
}
|
466
|
-
if (
|
467
|
-
throw new xrpc_server_1.
|
367
|
+
if (checkDeactivated && found.deactivatedAt) {
|
368
|
+
throw new xrpc_server_1.AuthRequiredError('Account is deactivated', 'AccountDeactivated');
|
468
369
|
}
|
469
|
-
throw err;
|
470
370
|
}
|
471
371
|
}
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
372
|
+
/**
|
373
|
+
* Wraps {@link jose.jwtVerify} into a function that also validates the token
|
374
|
+
* payload's type and wraps errors into {@link InvalidRequestError}.
|
375
|
+
*/
|
376
|
+
async verifyBearerJwt(req, { scopes, ...options }) {
|
377
|
+
const token = bearerTokenFromReq(req);
|
378
|
+
if (!token) {
|
379
|
+
throw new xrpc_server_1.AuthRequiredError(undefined, 'AuthMissing');
|
380
|
+
}
|
381
|
+
const { payload, protectedHeader } = await jose
|
382
|
+
.jwtVerify(token, this._jwtKey, { ...options, typ: undefined })
|
383
|
+
.catch((cause) => {
|
384
|
+
if (cause instanceof jose.errors.JWTExpired) {
|
385
|
+
throw new xrpc_server_1.InvalidRequestError('Token has expired', 'ExpiredToken', {
|
386
|
+
cause,
|
387
|
+
});
|
388
|
+
}
|
389
|
+
else {
|
390
|
+
throw new xrpc_server_1.InvalidRequestError('Token could not be verified', 'InvalidToken', { cause });
|
391
|
+
}
|
476
392
|
});
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
393
|
+
// @NOTE: the "typ" is now set in production environments, so we should be
|
394
|
+
// able to safely check it through jose.jwtVerify(). However, tests depend
|
395
|
+
// on @atproto/pds-entryway which does not set "typ" in the access tokens.
|
396
|
+
// For that reason, we still allow it to be missing.
|
397
|
+
if (protectedHeader.typ && options.typ !== protectedHeader.typ) {
|
398
|
+
throw new xrpc_server_1.InvalidRequestError('Invalid token type', 'InvalidToken');
|
399
|
+
}
|
400
|
+
const { sub, aud, scope, lxm, cnf, jti } = payload;
|
401
|
+
if (typeof lxm !== 'undefined') {
|
402
|
+
// Service auth tokens should never make it to here. But since service
|
403
|
+
// auth tokens do not have a "typ" header, the "typ" check above will not
|
404
|
+
// catch them. This check here is mainly to protect against the
|
405
|
+
// hypothetical case in which a PDS would issue service auth tokens using
|
406
|
+
// its private key.
|
407
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
408
|
+
}
|
409
|
+
if (typeof cnf !== 'undefined') {
|
410
|
+
// Proof-of-Possession (PoP) tokens are not allowed here
|
411
|
+
// https://www.rfc-editor.org/rfc/rfc7800.html
|
412
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
413
|
+
}
|
414
|
+
if (typeof sub !== 'string' || !sub.startsWith('did:')) {
|
415
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
416
|
+
}
|
417
|
+
if (typeof aud !== 'string' || !aud.startsWith('did:')) {
|
418
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
419
|
+
}
|
420
|
+
if (typeof jti !== 'string' && typeof jti !== 'undefined') {
|
421
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed token', 'InvalidToken');
|
422
|
+
}
|
423
|
+
if (!(0, auth_scope_1.isAuthScope)(scope) || !scopes.includes(scope)) {
|
424
|
+
throw new xrpc_server_1.InvalidRequestError('Bad token scope', 'InvalidToken');
|
425
|
+
}
|
426
|
+
return { sub, aud, jti, scope: scope };
|
486
427
|
}
|
487
|
-
async verifyServiceJwt(
|
488
|
-
this.setAuthHeaders(ctx);
|
428
|
+
async verifyServiceJwt(req, opts) {
|
489
429
|
const getSigningKey = async (iss, forceRefresh) => {
|
490
|
-
if (opts
|
430
|
+
if (opts?.iss && !opts.iss.includes(iss)) {
|
491
431
|
throw new xrpc_server_1.AuthRequiredError('Untrusted issuer', 'UntrustedIss');
|
492
432
|
}
|
493
433
|
const [did, serviceId] = iss.split('#');
|
@@ -506,60 +446,41 @@ class AuthVerifier {
|
|
506
446
|
}
|
507
447
|
return didKey;
|
508
448
|
};
|
509
|
-
const jwtStr = bearerTokenFromReq(
|
449
|
+
const jwtStr = bearerTokenFromReq(req);
|
510
450
|
if (!jwtStr) {
|
511
451
|
throw new xrpc_server_1.AuthRequiredError('missing jwt', 'MissingJwt');
|
512
452
|
}
|
513
|
-
const nsid = (0, xrpc_server_1.parseReqNsid)(
|
514
|
-
const payload = await (0, xrpc_server_1.verifyJwt)(jwtStr,
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
this.setAuthHeaders(ctx);
|
519
|
-
return {
|
520
|
-
credentials: null,
|
521
|
-
};
|
522
|
-
}
|
523
|
-
isUserOrAdmin(auth, did) {
|
524
|
-
if (!auth.credentials) {
|
525
|
-
return false;
|
526
|
-
}
|
527
|
-
else if (auth.credentials.type === 'admin_token') {
|
528
|
-
return true;
|
529
|
-
}
|
530
|
-
else {
|
531
|
-
return auth.credentials.did === did;
|
532
|
-
}
|
533
|
-
}
|
534
|
-
async jwtVerify(token, verifyOptions) {
|
535
|
-
try {
|
536
|
-
return await jose.jwtVerify(token, this._jwtKey, verifyOptions);
|
537
|
-
}
|
538
|
-
catch (err) {
|
539
|
-
if (err?.['code'] === 'ERR_JWT_EXPIRED') {
|
540
|
-
throw new xrpc_server_1.InvalidRequestError('Token has expired', 'ExpiredToken');
|
541
|
-
}
|
542
|
-
throw new xrpc_server_1.InvalidRequestError('Token could not be verified', 'InvalidToken');
|
543
|
-
}
|
544
|
-
}
|
545
|
-
setAuthHeaders(ctx) {
|
546
|
-
const res = 'res' in ctx ? ctx.res : null;
|
547
|
-
if (res) {
|
548
|
-
res.setHeader('Cache-Control', 'private');
|
549
|
-
vary(res, 'Authorization');
|
453
|
+
const nsid = (0, xrpc_server_1.parseReqNsid)(req);
|
454
|
+
const payload = await (0, xrpc_server_1.verifyJwt)(jwtStr, null, nsid, getSigningKey);
|
455
|
+
if (payload.aud !== this.dids.pds &&
|
456
|
+
(!this.dids.entryway || payload.aud !== this.dids.entryway)) {
|
457
|
+
throw new xrpc_server_1.AuthRequiredError('jwt audience does not match service did', 'BadJwtAudience');
|
550
458
|
}
|
459
|
+
return payload;
|
551
460
|
}
|
552
461
|
}
|
553
462
|
exports.AuthVerifier = AuthVerifier;
|
554
463
|
// HELPERS
|
555
464
|
// ---------
|
465
|
+
function isUserOrAdmin(auth, did) {
|
466
|
+
if (!auth.credentials) {
|
467
|
+
return false;
|
468
|
+
}
|
469
|
+
else if (auth.credentials.type === 'admin_token') {
|
470
|
+
return true;
|
471
|
+
}
|
472
|
+
else {
|
473
|
+
return auth.credentials.did === did;
|
474
|
+
}
|
475
|
+
}
|
556
476
|
var AuthType;
|
557
477
|
(function (AuthType) {
|
558
478
|
AuthType["BASIC"] = "Basic";
|
559
479
|
AuthType["BEARER"] = "Bearer";
|
560
480
|
AuthType["DPOP"] = "DPoP";
|
561
481
|
})(AuthType || (AuthType = {}));
|
562
|
-
const parseAuthorizationHeader = (
|
482
|
+
const parseAuthorizationHeader = (req) => {
|
483
|
+
const authorization = req.headers['authorization'];
|
563
484
|
if (!authorization)
|
564
485
|
return [null];
|
565
486
|
const result = authorization.split(' ');
|
@@ -573,26 +494,29 @@ const parseAuthorizationHeader = (authorization) => {
|
|
573
494
|
return [type, result[1]];
|
574
495
|
throw new xrpc_server_1.InvalidRequestError(`Unsupported authorization type: ${result[0]}`, 'InvalidToken');
|
575
496
|
};
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
const
|
582
|
-
const
|
583
|
-
|
497
|
+
/**
|
498
|
+
* @note Not all service auth tokens are guaranteed to have "lxm" claim, so this
|
499
|
+
* function should not be used to verify service auth tokens. It is only used to
|
500
|
+
* check if a token is definitely a service auth token.
|
501
|
+
*/
|
502
|
+
const isDefinitelyServiceAuth = (req) => {
|
503
|
+
const token = bearerTokenFromReq(req);
|
504
|
+
if (!token)
|
505
|
+
return false;
|
506
|
+
const payload = jose.decodeJwt(token);
|
507
|
+
return payload['lxm'] != null;
|
584
508
|
};
|
585
|
-
const
|
586
|
-
const [type] =
|
587
|
-
return type
|
509
|
+
const extractAuthType = (req) => {
|
510
|
+
const [type] = parseAuthorizationHeader(req);
|
511
|
+
return type;
|
588
512
|
};
|
589
513
|
const bearerTokenFromReq = (req) => {
|
590
|
-
const [type, token] =
|
514
|
+
const [type, token] = parseAuthorizationHeader(req);
|
591
515
|
return type === AuthType.BEARER ? token : null;
|
592
516
|
};
|
593
|
-
const parseBasicAuth = (
|
517
|
+
const parseBasicAuth = (req) => {
|
594
518
|
try {
|
595
|
-
const [type, b64] =
|
519
|
+
const [type, b64] = parseAuthorizationHeader(req);
|
596
520
|
if (type !== AuthType.BASIC)
|
597
521
|
return null;
|
598
522
|
const decoded = Buffer.from(b64, 'base64').toString('utf8');
|
@@ -608,33 +532,18 @@ const parseBasicAuth = (authorizationHeader) => {
|
|
608
532
|
return null;
|
609
533
|
}
|
610
534
|
};
|
611
|
-
exports.parseBasicAuth = parseBasicAuth;
|
612
|
-
const authScopes = new Set(Object.values(AuthScope));
|
613
|
-
const isAuthScope = (val) => {
|
614
|
-
return authScopes.has(val);
|
615
|
-
};
|
616
535
|
const createSecretKeyObject = (secret) => {
|
617
536
|
return (0, node_crypto_1.createSecretKey)(Buffer.from(secret));
|
618
537
|
};
|
619
538
|
exports.createSecretKeyObject = createSecretKeyObject;
|
539
|
+
const keyEncoder = new key_encoder_1.default('secp256k1');
|
620
540
|
const createPublicKeyObject = (publicKeyHex) => {
|
621
541
|
const key = keyEncoder.encodePublic(publicKeyHex, 'raw', 'pem');
|
622
542
|
return (0, node_crypto_1.createPublicKey)({ format: 'pem', key });
|
623
543
|
};
|
624
544
|
exports.createPublicKeyObject = createPublicKeyObject;
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
if (current == null || typeof current === 'number') {
|
629
|
-
res.setHeader('Vary', value);
|
630
|
-
}
|
631
|
-
else {
|
632
|
-
const alreadyIncluded = Array.isArray(current)
|
633
|
-
? current.some((value) => value.includes(value))
|
634
|
-
: current.includes(value);
|
635
|
-
if (!alreadyIncluded) {
|
636
|
-
res.appendHeader('Vary', value);
|
637
|
-
}
|
638
|
-
}
|
545
|
+
function setAuthHeaders(res) {
|
546
|
+
res.setHeader('Cache-Control', 'private');
|
547
|
+
(0, http_1.appendVary)(res, 'Authorization');
|
639
548
|
}
|
640
549
|
//# sourceMappingURL=auth-verifier.js.map
|