najm-auth 3.3.2 → 3.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/README.md +45 -18
- package/dist/{NajmAuthClient-BBl-GRis.d.ts → NajmAuthClient-BygfBCpF.d.ts} +2 -1
- package/dist/client/index.d.ts +3 -3
- package/dist/client/index.js +3 -0
- package/dist/client/react/index.d.ts +23 -3
- package/dist/client/react/index.js +63 -6
- package/dist/client/server/index.d.ts +4 -4
- package/dist/client/server/index.js +3 -0
- package/dist/client/server/react.d.ts +2 -2
- package/dist/{getSession-BthP85UA.d.ts → getSession-DBX8XpsR.d.ts} +1 -1
- package/dist/index.d.ts +43 -12
- package/dist/index.js +440 -169
- package/dist/schema/pg.d.ts +2 -2
- package/dist/schema/sqlite.d.ts +4 -4
- package/dist/{types-BaSfgxqE.d.ts → types-CI2t8wpJ.d.ts} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5399,7 +5399,7 @@ function toSingular(plural) {
|
|
|
5399
5399
|
}
|
|
5400
5400
|
__name(toSingular, "toSingular");
|
|
5401
5401
|
function createResourceGuards(ownershipClass, resourceType, resource, options) {
|
|
5402
|
-
var
|
|
5402
|
+
var _a28, _b15;
|
|
5403
5403
|
const writeGuard = options?.adminGuard ?? isAdmin;
|
|
5404
5404
|
let AccessGuard = class AccessGuard {
|
|
5405
5405
|
static {
|
|
@@ -5420,7 +5420,7 @@ function createResourceGuards(ownershipClass, resourceType, resource, options) {
|
|
|
5420
5420
|
__param12(1, Params4("id")),
|
|
5421
5421
|
__metadata31("design:type", Function),
|
|
5422
5422
|
__metadata31("design:paramtypes", [Object, String]),
|
|
5423
|
-
__metadata31("design:returntype", typeof (
|
|
5423
|
+
__metadata31("design:returntype", typeof (_a28 = typeof Promise !== "undefined" && Promise) === "function" ? _a28 : Object)
|
|
5424
5424
|
], AccessGuard.prototype, "canActivate", null);
|
|
5425
5425
|
AccessGuard = __decorate31([
|
|
5426
5426
|
Injectable15()
|
|
@@ -5581,7 +5581,7 @@ function configureOwnership(config) {
|
|
|
5581
5581
|
Injectable15()
|
|
5582
5582
|
], GeneratedOwnershipService);
|
|
5583
5583
|
function bodyGuard(resourceType, bodyField, optional = false) {
|
|
5584
|
-
var
|
|
5584
|
+
var _a28;
|
|
5585
5585
|
let BodyAccessGuard = class BodyAccessGuard {
|
|
5586
5586
|
static {
|
|
5587
5587
|
__name(this, "BodyAccessGuard");
|
|
@@ -5603,7 +5603,7 @@ function configureOwnership(config) {
|
|
|
5603
5603
|
__param12(1, Body6()),
|
|
5604
5604
|
__metadata31("design:type", Function),
|
|
5605
5605
|
__metadata31("design:paramtypes", [Object, Object]),
|
|
5606
|
-
__metadata31("design:returntype", typeof (
|
|
5606
|
+
__metadata31("design:returntype", typeof (_a28 = typeof Promise !== "undefined" && Promise) === "function" ? _a28 : Object)
|
|
5607
5607
|
], BodyAccessGuard.prototype, "canActivate", null);
|
|
5608
5608
|
BodyAccessGuard = __decorate31([
|
|
5609
5609
|
Injectable15()
|
|
@@ -6158,17 +6158,162 @@ GoogleOAuthProvider = __decorate34([
|
|
|
6158
6158
|
__metadata34("design:paramtypes", [typeof (_a21 = typeof GoogleTokenVerifier !== "undefined" && GoogleTokenVerifier) === "function" ? _a21 : Object])
|
|
6159
6159
|
], GoogleOAuthProvider);
|
|
6160
6160
|
|
|
6161
|
+
// src/oauth/github/GitHubOAuthProvider.ts
|
|
6162
|
+
import { Inject as Inject19, Injectable as Injectable19 } from "najm-core";
|
|
6163
|
+
var __decorate35 = function(decorators, target, key, desc) {
|
|
6164
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6165
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6166
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6167
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6168
|
+
};
|
|
6169
|
+
var __metadata35 = function(k, v) {
|
|
6170
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6171
|
+
};
|
|
6172
|
+
var AUTHORIZATION_ENDPOINT2 = "https://github.com/login/oauth/authorize";
|
|
6173
|
+
var TOKEN_ENDPOINT2 = "https://github.com/login/oauth/access_token";
|
|
6174
|
+
var USER_ENDPOINT = "https://api.github.com/user";
|
|
6175
|
+
var EMAILS_ENDPOINT = "https://api.github.com/user/emails";
|
|
6176
|
+
var API_VERSION = "2022-11-28";
|
|
6177
|
+
var GitHubOAuthProvider = class GitHubOAuthProvider2 {
|
|
6178
|
+
static {
|
|
6179
|
+
__name(this, "GitHubOAuthProvider");
|
|
6180
|
+
}
|
|
6181
|
+
config;
|
|
6182
|
+
authorizationUrl(attempt, codeChallenge) {
|
|
6183
|
+
const github = this.githubConfig();
|
|
6184
|
+
const url = new URL(AUTHORIZATION_ENDPOINT2);
|
|
6185
|
+
url.search = new URLSearchParams({
|
|
6186
|
+
client_id: github.clientId,
|
|
6187
|
+
redirect_uri: github.callbackUrl,
|
|
6188
|
+
scope: "user:email",
|
|
6189
|
+
state: attempt.state,
|
|
6190
|
+
code_challenge: codeChallenge,
|
|
6191
|
+
code_challenge_method: "S256"
|
|
6192
|
+
}).toString();
|
|
6193
|
+
return url.toString();
|
|
6194
|
+
}
|
|
6195
|
+
async exchange(code, attempt) {
|
|
6196
|
+
const github = this.githubConfig();
|
|
6197
|
+
const token = await this.exchangeCode(code, attempt.codeVerifier, github);
|
|
6198
|
+
const headers = {
|
|
6199
|
+
accept: "application/vnd.github+json",
|
|
6200
|
+
authorization: `Bearer ${token}`,
|
|
6201
|
+
"user-agent": "najm-auth",
|
|
6202
|
+
"x-github-api-version": API_VERSION
|
|
6203
|
+
};
|
|
6204
|
+
const [user, emails] = await Promise.all([
|
|
6205
|
+
this.fetchJson(USER_ENDPOINT, headers),
|
|
6206
|
+
this.fetchJson(EMAILS_ENDPOINT, headers)
|
|
6207
|
+
]);
|
|
6208
|
+
const primary = Array.isArray(emails) ? emails.find((entry) => entry.primary === true && entry.verified === true) : void 0;
|
|
6209
|
+
const email2 = primary?.email?.trim().toLowerCase();
|
|
6210
|
+
const providerAccountId = user.id === void 0 ? "" : String(user.id);
|
|
6211
|
+
const login = user.login?.trim() ?? "";
|
|
6212
|
+
if (!providerAccountId || !login || !email2) {
|
|
6213
|
+
throw new OAuthFlowError("oauth_verified_email_required", 403);
|
|
6214
|
+
}
|
|
6215
|
+
return {
|
|
6216
|
+
provider: "github",
|
|
6217
|
+
providerAccountId,
|
|
6218
|
+
email: email2,
|
|
6219
|
+
emailVerified: true,
|
|
6220
|
+
login,
|
|
6221
|
+
name: user.name?.trim() || login,
|
|
6222
|
+
picture: user.avatar_url?.trim() || void 0
|
|
6223
|
+
};
|
|
6224
|
+
}
|
|
6225
|
+
async exchangeCode(code, codeVerifier, github) {
|
|
6226
|
+
let response;
|
|
6227
|
+
try {
|
|
6228
|
+
response = await fetch(TOKEN_ENDPOINT2, {
|
|
6229
|
+
method: "POST",
|
|
6230
|
+
headers: {
|
|
6231
|
+
accept: "application/json",
|
|
6232
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
6233
|
+
},
|
|
6234
|
+
body: new URLSearchParams({
|
|
6235
|
+
client_id: github.clientId,
|
|
6236
|
+
client_secret: github.clientSecret,
|
|
6237
|
+
code,
|
|
6238
|
+
redirect_uri: github.callbackUrl,
|
|
6239
|
+
code_verifier: codeVerifier
|
|
6240
|
+
}),
|
|
6241
|
+
signal: AbortSignal.timeout(15e3)
|
|
6242
|
+
});
|
|
6243
|
+
} catch {
|
|
6244
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6245
|
+
}
|
|
6246
|
+
if (!response.ok)
|
|
6247
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6248
|
+
let body;
|
|
6249
|
+
try {
|
|
6250
|
+
body = await response.json();
|
|
6251
|
+
} catch {
|
|
6252
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6253
|
+
}
|
|
6254
|
+
const accessToken = body.access_token;
|
|
6255
|
+
if (typeof accessToken !== "string" || !accessToken) {
|
|
6256
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6257
|
+
}
|
|
6258
|
+
return accessToken;
|
|
6259
|
+
}
|
|
6260
|
+
async fetchJson(url, headers) {
|
|
6261
|
+
let response;
|
|
6262
|
+
try {
|
|
6263
|
+
response = await fetch(url, {
|
|
6264
|
+
headers,
|
|
6265
|
+
signal: AbortSignal.timeout(15e3)
|
|
6266
|
+
});
|
|
6267
|
+
} catch {
|
|
6268
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6269
|
+
}
|
|
6270
|
+
if (!response.ok)
|
|
6271
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6272
|
+
try {
|
|
6273
|
+
return await response.json();
|
|
6274
|
+
} catch {
|
|
6275
|
+
throw new OAuthFlowError("oauth_provider_error", 502);
|
|
6276
|
+
}
|
|
6277
|
+
}
|
|
6278
|
+
githubConfig() {
|
|
6279
|
+
const github = this.config.oauth?.github;
|
|
6280
|
+
if (!github)
|
|
6281
|
+
throw new OAuthFlowError("oauth_provider_disabled", 404);
|
|
6282
|
+
return github;
|
|
6283
|
+
}
|
|
6284
|
+
};
|
|
6285
|
+
__decorate35([
|
|
6286
|
+
Inject19(AUTH_CONFIG),
|
|
6287
|
+
__metadata35("design:type", Object)
|
|
6288
|
+
], GitHubOAuthProvider.prototype, "config", void 0);
|
|
6289
|
+
GitHubOAuthProvider = __decorate35([
|
|
6290
|
+
Injectable19()
|
|
6291
|
+
], GitHubOAuthProvider);
|
|
6292
|
+
|
|
6293
|
+
// src/oauth/GitHubOAuthController.ts
|
|
6294
|
+
import { createHash as createHash5 } from "crypto";
|
|
6295
|
+
import { Controller as Controller6, Ctx as Ctx2, Get as Get5, Post as Post6, Query as Query2, User as User5 } from "najm-core";
|
|
6296
|
+
import { RateLimit as RateLimit3 } from "najm-rate";
|
|
6297
|
+
|
|
6298
|
+
// src/oauth/OAuthService.ts
|
|
6299
|
+
import { Inject as Inject22, Injectable as Injectable22, Log as Log2 } from "najm-core";
|
|
6300
|
+
|
|
6301
|
+
// src/oauth/OAuthAccountService.ts
|
|
6302
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
6303
|
+
import { Inject as Inject21, Injectable as Injectable20 } from "najm-core";
|
|
6304
|
+
import { Transaction as Transaction5 } from "najm-database";
|
|
6305
|
+
|
|
6161
6306
|
// src/oauth/OAuthAccountRepository.ts
|
|
6162
6307
|
import { and as and6, eq as eq9 } from "drizzle-orm";
|
|
6163
|
-
import { Inject as
|
|
6308
|
+
import { Inject as Inject20, Repository as Repository7 } from "najm-core";
|
|
6164
6309
|
import { DB as DB7 } from "najm-database";
|
|
6165
|
-
var
|
|
6310
|
+
var __decorate36 = function(decorators, target, key, desc) {
|
|
6166
6311
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6167
6312
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6168
6313
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6169
6314
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6170
6315
|
};
|
|
6171
|
-
var
|
|
6316
|
+
var __metadata36 = function(k, v) {
|
|
6172
6317
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6173
6318
|
};
|
|
6174
6319
|
var OAuthAccountRepository = class OAuthAccountRepository2 {
|
|
@@ -6196,29 +6341,26 @@ var OAuthAccountRepository = class OAuthAccountRepository2 {
|
|
|
6196
6341
|
return account;
|
|
6197
6342
|
}
|
|
6198
6343
|
};
|
|
6199
|
-
|
|
6344
|
+
__decorate36([
|
|
6200
6345
|
DB7(),
|
|
6201
|
-
|
|
6346
|
+
__metadata36("design:type", Object)
|
|
6202
6347
|
], OAuthAccountRepository.prototype, "db", void 0);
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6348
|
+
__decorate36([
|
|
6349
|
+
Inject20(AUTH_SCHEMA),
|
|
6350
|
+
__metadata36("design:type", Object)
|
|
6206
6351
|
], OAuthAccountRepository.prototype, "schema", void 0);
|
|
6207
|
-
OAuthAccountRepository =
|
|
6352
|
+
OAuthAccountRepository = __decorate36([
|
|
6208
6353
|
Repository7()
|
|
6209
6354
|
], OAuthAccountRepository);
|
|
6210
6355
|
|
|
6211
6356
|
// src/oauth/OAuthAccountService.ts
|
|
6212
|
-
|
|
6213
|
-
import { Inject as Inject20, Injectable as Injectable19 } from "najm-core";
|
|
6214
|
-
import { Transaction as Transaction5 } from "najm-database";
|
|
6215
|
-
var __decorate36 = function(decorators, target, key, desc) {
|
|
6357
|
+
var __decorate37 = function(decorators, target, key, desc) {
|
|
6216
6358
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6217
6359
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6218
6360
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6219
6361
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6220
6362
|
};
|
|
6221
|
-
var
|
|
6363
|
+
var __metadata37 = function(k, v) {
|
|
6222
6364
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6223
6365
|
};
|
|
6224
6366
|
var _a22;
|
|
@@ -6237,18 +6379,18 @@ var OAuthAccountService = class OAuthAccountService2 {
|
|
|
6237
6379
|
this.users = users;
|
|
6238
6380
|
}
|
|
6239
6381
|
async resolveForLogin(identity) {
|
|
6240
|
-
const linked = await this.accounts.getByProviderAccount(
|
|
6382
|
+
const linked = await this.accounts.getByProviderAccount(identity.provider, identity.providerAccountId);
|
|
6241
6383
|
if (linked)
|
|
6242
6384
|
return this.users.getById(linked.userId);
|
|
6243
6385
|
const existingUser = await this.users.findByEmailInsensitive(identity.email);
|
|
6244
6386
|
if (existingUser) {
|
|
6245
|
-
if (!this.
|
|
6387
|
+
if (!this.providerConfig(identity.provider).autoLinkVerifiedEmail) {
|
|
6246
6388
|
throw new OAuthFlowError("oauth_account_link_required", 409);
|
|
6247
6389
|
}
|
|
6248
6390
|
await this.createLink(existingUser.id, identity);
|
|
6249
6391
|
return this.users.getById(existingUser.id);
|
|
6250
6392
|
}
|
|
6251
|
-
if (!this.
|
|
6393
|
+
if (!this.providerConfig(identity.provider).allowSignup) {
|
|
6252
6394
|
throw new OAuthFlowError("oauth_signup_disabled", 403);
|
|
6253
6395
|
}
|
|
6254
6396
|
const password = `${randomBytes3(32).toString("base64url")}Aa1`;
|
|
@@ -6266,13 +6408,13 @@ var OAuthAccountService = class OAuthAccountService2 {
|
|
|
6266
6408
|
const user = await this.users.getById(userId);
|
|
6267
6409
|
if (user.status !== "active")
|
|
6268
6410
|
throw new OAuthFlowError("oauth_account_inactive", 403);
|
|
6269
|
-
const providerAccount = await this.accounts.getByProviderAccount(
|
|
6411
|
+
const providerAccount = await this.accounts.getByProviderAccount(identity.provider, identity.providerAccountId);
|
|
6270
6412
|
if (providerAccount && providerAccount.userId !== userId) {
|
|
6271
6413
|
throw new OAuthFlowError("oauth_provider_account_linked", 409);
|
|
6272
6414
|
}
|
|
6273
6415
|
if (providerAccount)
|
|
6274
6416
|
return user;
|
|
6275
|
-
const userProvider = await this.accounts.getByUserProvider(userId,
|
|
6417
|
+
const userProvider = await this.accounts.getByUserProvider(userId, identity.provider);
|
|
6276
6418
|
if (userProvider && userProvider.providerAccountId !== identity.providerAccountId) {
|
|
6277
6419
|
throw new OAuthFlowError("oauth_user_provider_linked", 409);
|
|
6278
6420
|
}
|
|
@@ -6283,69 +6425,61 @@ var OAuthAccountService = class OAuthAccountService2 {
|
|
|
6283
6425
|
async createLink(userId, identity) {
|
|
6284
6426
|
const created = await this.accounts.create({
|
|
6285
6427
|
userId,
|
|
6286
|
-
provider:
|
|
6428
|
+
provider: identity.provider,
|
|
6287
6429
|
providerAccountId: identity.providerAccountId
|
|
6288
6430
|
});
|
|
6289
6431
|
if (created)
|
|
6290
6432
|
return;
|
|
6291
|
-
const linked = await this.accounts.getByProviderAccount(
|
|
6433
|
+
const linked = await this.accounts.getByProviderAccount(identity.provider, identity.providerAccountId);
|
|
6292
6434
|
if (!linked || linked.userId !== userId) {
|
|
6293
6435
|
throw new OAuthFlowError("oauth_provider_account_linked", 409);
|
|
6294
6436
|
}
|
|
6295
6437
|
}
|
|
6296
|
-
|
|
6297
|
-
const
|
|
6298
|
-
if (!
|
|
6438
|
+
providerConfig(provider) {
|
|
6439
|
+
const providerConfig = this.config.oauth?.[provider];
|
|
6440
|
+
if (!providerConfig)
|
|
6299
6441
|
throw new OAuthFlowError("oauth_provider_disabled", 404);
|
|
6300
|
-
return
|
|
6442
|
+
return providerConfig;
|
|
6301
6443
|
}
|
|
6302
6444
|
};
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6445
|
+
__decorate37([
|
|
6446
|
+
Inject21(AUTH_CONFIG),
|
|
6447
|
+
__metadata37("design:type", Object)
|
|
6306
6448
|
], OAuthAccountService.prototype, "config", void 0);
|
|
6307
|
-
|
|
6449
|
+
__decorate37([
|
|
6308
6450
|
Transaction5(),
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6451
|
+
__metadata37("design:type", Function),
|
|
6452
|
+
__metadata37("design:paramtypes", [Object]),
|
|
6453
|
+
__metadata37("design:returntype", typeof (_c9 = typeof Promise !== "undefined" && Promise) === "function" ? _c9 : Object)
|
|
6312
6454
|
], OAuthAccountService.prototype, "resolveForLogin", null);
|
|
6313
|
-
|
|
6455
|
+
__decorate37([
|
|
6314
6456
|
Transaction5(),
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6457
|
+
__metadata37("design:type", Function),
|
|
6458
|
+
__metadata37("design:paramtypes", [String, Object]),
|
|
6459
|
+
__metadata37("design:returntype", typeof (_d7 = typeof Promise !== "undefined" && Promise) === "function" ? _d7 : Object)
|
|
6318
6460
|
], OAuthAccountService.prototype, "linkUser", null);
|
|
6319
|
-
OAuthAccountService =
|
|
6320
|
-
|
|
6321
|
-
|
|
6461
|
+
OAuthAccountService = __decorate37([
|
|
6462
|
+
Injectable20(),
|
|
6463
|
+
__metadata37("design:paramtypes", [typeof (_a22 = typeof OAuthAccountRepository !== "undefined" && OAuthAccountRepository) === "function" ? _a22 : Object, typeof (_b12 = typeof UserService !== "undefined" && UserService) === "function" ? _b12 : Object])
|
|
6322
6464
|
], OAuthAccountService);
|
|
6323
6465
|
|
|
6324
|
-
// src/oauth/OAuthController.ts
|
|
6325
|
-
import { createHash as createHash5 } from "crypto";
|
|
6326
|
-
import { Controller as Controller6, Ctx as Ctx2, Get as Get5, Post as Post6, Query as Query2, User as User5 } from "najm-core";
|
|
6327
|
-
import { RateLimit as RateLimit3 } from "najm-rate";
|
|
6328
|
-
|
|
6329
|
-
// src/oauth/OAuthService.ts
|
|
6330
|
-
import { Inject as Inject21, Injectable as Injectable21, Log as Log2 } from "najm-core";
|
|
6331
|
-
|
|
6332
6466
|
// src/oauth/OAuthStateService.ts
|
|
6333
6467
|
import { createHash as createHash4, randomBytes as randomBytes4, timingSafeEqual } from "crypto";
|
|
6334
|
-
import { Injectable as
|
|
6468
|
+
import { Injectable as Injectable21 } from "najm-core";
|
|
6335
6469
|
import { CookieService as CookieService3 } from "najm-cookies";
|
|
6336
|
-
var
|
|
6470
|
+
var __decorate38 = function(decorators, target, key, desc) {
|
|
6337
6471
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6338
6472
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6339
6473
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6340
6474
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6341
6475
|
};
|
|
6342
|
-
var
|
|
6476
|
+
var __metadata38 = function(k, v) {
|
|
6343
6477
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6344
6478
|
};
|
|
6345
6479
|
var _a23;
|
|
6346
6480
|
var _b13;
|
|
6347
6481
|
var ATTEMPT_TTL_MS = 10 * 60 * 1e3;
|
|
6348
|
-
var COOKIE_PREFIX = "najm.oauth.
|
|
6482
|
+
var COOKIE_PREFIX = "najm.oauth.";
|
|
6349
6483
|
var OAuthStateService = class OAuthStateService2 {
|
|
6350
6484
|
static {
|
|
6351
6485
|
__name(this, "OAuthStateService");
|
|
@@ -6360,7 +6494,7 @@ var OAuthStateService = class OAuthStateService2 {
|
|
|
6360
6494
|
const state = randomBytes4(32).toString("base64url");
|
|
6361
6495
|
const codeVerifier = randomBytes4(48).toString("base64url");
|
|
6362
6496
|
const attempt = {
|
|
6363
|
-
provider:
|
|
6497
|
+
provider: input.provider,
|
|
6364
6498
|
intent: input.intent,
|
|
6365
6499
|
state,
|
|
6366
6500
|
nonce: randomBytes4(32).toString("base64url"),
|
|
@@ -6370,7 +6504,7 @@ var OAuthStateService = class OAuthStateService2 {
|
|
|
6370
6504
|
sessionVersion: input.sessionVersion,
|
|
6371
6505
|
createdAt: Date.now()
|
|
6372
6506
|
};
|
|
6373
|
-
this.cookies.set(this.cookieName(state), this.encryption.encrypt(JSON.stringify(attempt)), {
|
|
6507
|
+
this.cookies.set(this.cookieName(input.provider, state), this.encryption.encrypt(JSON.stringify(attempt)), {
|
|
6374
6508
|
httpOnly: true,
|
|
6375
6509
|
sameSite: "Lax",
|
|
6376
6510
|
path: "/",
|
|
@@ -6381,10 +6515,10 @@ var OAuthStateService = class OAuthStateService2 {
|
|
|
6381
6515
|
codeChallenge: createHash4("sha256").update(codeVerifier).digest("base64url")
|
|
6382
6516
|
};
|
|
6383
6517
|
}
|
|
6384
|
-
consume(state) {
|
|
6518
|
+
consume(provider, state) {
|
|
6385
6519
|
if (!this.isSafeState(state))
|
|
6386
6520
|
throw new OAuthFlowError("oauth_state_invalid");
|
|
6387
|
-
const name = this.cookieName(state);
|
|
6521
|
+
const name = this.cookieName(provider, state);
|
|
6388
6522
|
const encrypted = this.cookies.get(name);
|
|
6389
6523
|
this.cookies.delete(name, { path: "/" });
|
|
6390
6524
|
if (!encrypted)
|
|
@@ -6396,7 +6530,7 @@ var OAuthStateService = class OAuthStateService2 {
|
|
|
6396
6530
|
if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) {
|
|
6397
6531
|
throw new OAuthFlowError("oauth_state_invalid");
|
|
6398
6532
|
}
|
|
6399
|
-
if (attempt.provider !==
|
|
6533
|
+
if (attempt.provider !== provider || Date.now() - attempt.createdAt > ATTEMPT_TTL_MS) {
|
|
6400
6534
|
throw new OAuthFlowError("oauth_state_invalid");
|
|
6401
6535
|
}
|
|
6402
6536
|
attempt.returnTo = this.validateReturnTo(attempt.returnTo);
|
|
@@ -6425,26 +6559,26 @@ var OAuthStateService = class OAuthStateService2 {
|
|
|
6425
6559
|
throw new OAuthFlowError("oauth_redirect_invalid");
|
|
6426
6560
|
}
|
|
6427
6561
|
}
|
|
6428
|
-
cookieName(state) {
|
|
6429
|
-
return `${COOKIE_PREFIX}${state}`;
|
|
6562
|
+
cookieName(provider, state) {
|
|
6563
|
+
return `${COOKIE_PREFIX}${provider}.${state}`;
|
|
6430
6564
|
}
|
|
6431
6565
|
isSafeState(state) {
|
|
6432
6566
|
return /^[A-Za-z0-9_-]{40,128}$/.test(state);
|
|
6433
6567
|
}
|
|
6434
6568
|
};
|
|
6435
|
-
OAuthStateService =
|
|
6436
|
-
|
|
6437
|
-
|
|
6569
|
+
OAuthStateService = __decorate38([
|
|
6570
|
+
Injectable21(),
|
|
6571
|
+
__metadata38("design:paramtypes", [typeof (_a23 = typeof CookieService3 !== "undefined" && CookieService3) === "function" ? _a23 : Object, typeof (_b13 = typeof EncryptionService !== "undefined" && EncryptionService) === "function" ? _b13 : Object])
|
|
6438
6572
|
], OAuthStateService);
|
|
6439
6573
|
|
|
6440
6574
|
// src/oauth/OAuthService.ts
|
|
6441
|
-
var
|
|
6575
|
+
var __decorate39 = function(decorators, target, key, desc) {
|
|
6442
6576
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6443
6577
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6444
6578
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6445
6579
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6446
6580
|
};
|
|
6447
|
-
var
|
|
6581
|
+
var __metadata39 = function(k, v) {
|
|
6448
6582
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6449
6583
|
};
|
|
6450
6584
|
var _a24;
|
|
@@ -6454,12 +6588,14 @@ var _d8;
|
|
|
6454
6588
|
var _e5;
|
|
6455
6589
|
var _f5;
|
|
6456
6590
|
var _g4;
|
|
6591
|
+
var _h3;
|
|
6457
6592
|
var OAuthService = class OAuthService2 {
|
|
6458
6593
|
static {
|
|
6459
6594
|
__name(this, "OAuthService");
|
|
6460
6595
|
}
|
|
6461
6596
|
state;
|
|
6462
6597
|
google;
|
|
6598
|
+
github;
|
|
6463
6599
|
accounts;
|
|
6464
6600
|
sessions;
|
|
6465
6601
|
tokens;
|
|
@@ -6467,9 +6603,10 @@ var OAuthService = class OAuthService2 {
|
|
|
6467
6603
|
requirements;
|
|
6468
6604
|
config;
|
|
6469
6605
|
logger;
|
|
6470
|
-
constructor(state, google, accounts, sessions, tokens, users, requirements) {
|
|
6606
|
+
constructor(state, google, github, accounts, sessions, tokens, users, requirements) {
|
|
6471
6607
|
this.state = state;
|
|
6472
6608
|
this.google = google;
|
|
6609
|
+
this.github = github;
|
|
6473
6610
|
this.accounts = accounts;
|
|
6474
6611
|
this.sessions = sessions;
|
|
6475
6612
|
this.tokens = tokens;
|
|
@@ -6477,36 +6614,59 @@ var OAuthService = class OAuthService2 {
|
|
|
6477
6614
|
this.requirements = requirements;
|
|
6478
6615
|
}
|
|
6479
6616
|
startGoogleLogin(returnTo) {
|
|
6480
|
-
this.
|
|
6481
|
-
|
|
6482
|
-
|
|
6617
|
+
return this.startLogin("google", returnTo);
|
|
6618
|
+
}
|
|
6619
|
+
startGitHubLogin(returnTo) {
|
|
6620
|
+
return this.startLogin("github", returnTo);
|
|
6621
|
+
}
|
|
6622
|
+
startGoogleLink(userId, returnTo) {
|
|
6623
|
+
return this.startLink("google", userId, returnTo);
|
|
6624
|
+
}
|
|
6625
|
+
startGitHubLink(userId, returnTo) {
|
|
6626
|
+
return this.startLink("github", userId, returnTo);
|
|
6627
|
+
}
|
|
6628
|
+
finishGoogleCallback(params) {
|
|
6629
|
+
return this.finishCallback("google", params);
|
|
6630
|
+
}
|
|
6631
|
+
finishGitHubCallback(params) {
|
|
6632
|
+
return this.finishCallback("github", params);
|
|
6633
|
+
}
|
|
6634
|
+
startLogin(provider, returnTo) {
|
|
6635
|
+
this.providerConfig(provider);
|
|
6636
|
+
const { attempt, codeChallenge } = this.state.create({
|
|
6637
|
+
provider,
|
|
6638
|
+
intent: "login",
|
|
6639
|
+
returnTo
|
|
6640
|
+
});
|
|
6641
|
+
return this.provider(provider).authorizationUrl(attempt, codeChallenge);
|
|
6483
6642
|
}
|
|
6484
|
-
async
|
|
6485
|
-
this.
|
|
6643
|
+
async startLink(provider, userId, returnTo) {
|
|
6644
|
+
this.providerConfig(provider);
|
|
6486
6645
|
const user = await this.users.getById(userId);
|
|
6487
6646
|
if (user.status !== "active")
|
|
6488
6647
|
throw new OAuthFlowError("oauth_account_inactive", 403);
|
|
6489
6648
|
const sessionVersion = await this.tokens.getSessionVersion(userId);
|
|
6490
6649
|
const { attempt, codeChallenge } = this.state.create({
|
|
6650
|
+
provider,
|
|
6491
6651
|
intent: "link",
|
|
6492
6652
|
returnTo,
|
|
6493
6653
|
userId,
|
|
6494
6654
|
sessionVersion
|
|
6495
6655
|
});
|
|
6496
|
-
return { authorizationUrl: this.
|
|
6656
|
+
return { authorizationUrl: this.provider(provider).authorizationUrl(attempt, codeChallenge) };
|
|
6497
6657
|
}
|
|
6498
|
-
async
|
|
6658
|
+
async finishCallback(provider, params) {
|
|
6499
6659
|
try {
|
|
6500
|
-
this.
|
|
6660
|
+
this.providerConfig(provider);
|
|
6501
6661
|
if (!params.state)
|
|
6502
6662
|
throw new OAuthFlowError("oauth_state_invalid");
|
|
6503
|
-
const attempt = this.state.consume(params.state);
|
|
6663
|
+
const attempt = this.state.consume(provider, params.state);
|
|
6504
6664
|
if (params.error) {
|
|
6505
6665
|
throw new OAuthFlowError(params.error === "access_denied" ? "oauth_access_denied" : "oauth_provider_error");
|
|
6506
6666
|
}
|
|
6507
6667
|
if (!params.code)
|
|
6508
6668
|
throw new OAuthFlowError("oauth_provider_error");
|
|
6509
|
-
const identity = await this.
|
|
6669
|
+
const identity = await this.provider(provider).exchange(params.code, attempt);
|
|
6510
6670
|
if (attempt.intent === "link") {
|
|
6511
6671
|
if (!attempt.userId || attempt.sessionVersion === void 0) {
|
|
6512
6672
|
throw new OAuthFlowError("oauth_state_invalid");
|
|
@@ -6523,25 +6683,26 @@ var OAuthService = class OAuthService2 {
|
|
|
6523
6683
|
}
|
|
6524
6684
|
await this.sessions.establish(user);
|
|
6525
6685
|
}
|
|
6526
|
-
return this.frontendSuccessUrl(attempt.returnTo, attempt.intent);
|
|
6686
|
+
return this.frontendSuccessUrl(provider, attempt.returnTo, attempt.intent);
|
|
6527
6687
|
} catch (error) {
|
|
6528
6688
|
const code = this.publicErrorCode(error);
|
|
6529
|
-
this.logger.warn("
|
|
6530
|
-
return this.frontendErrorUrl(code);
|
|
6689
|
+
this.logger.warn("OAuth callback failed", { provider, code });
|
|
6690
|
+
return this.frontendErrorUrl(provider, code);
|
|
6531
6691
|
}
|
|
6532
6692
|
}
|
|
6533
|
-
frontendSuccessUrl(returnTo, mode) {
|
|
6534
|
-
const
|
|
6535
|
-
const url = new URL(
|
|
6536
|
-
url.searchParams.set("provider",
|
|
6693
|
+
frontendSuccessUrl(provider, returnTo, mode) {
|
|
6694
|
+
const providerConfig = this.providerConfig(provider);
|
|
6695
|
+
const url = new URL(providerConfig.frontendCallbackPath, this.config.frontendUrl);
|
|
6696
|
+
url.searchParams.set("provider", provider);
|
|
6537
6697
|
url.searchParams.set("mode", mode);
|
|
6538
6698
|
url.searchParams.set("returnTo", this.state.validateReturnTo(returnTo));
|
|
6539
6699
|
return url.toString();
|
|
6540
6700
|
}
|
|
6541
|
-
frontendErrorUrl(code) {
|
|
6542
|
-
const path2 = this.config.oauth?.
|
|
6701
|
+
frontendErrorUrl(provider, code) {
|
|
6702
|
+
const path2 = this.config.oauth?.[provider]?.errorRedirectPath ?? "/login";
|
|
6543
6703
|
const url = new URL(path2, this.config.frontendUrl);
|
|
6544
6704
|
url.searchParams.set("oauthError", code);
|
|
6705
|
+
url.searchParams.set("provider", provider);
|
|
6545
6706
|
return url.toString();
|
|
6546
6707
|
}
|
|
6547
6708
|
publicErrorCode(error) {
|
|
@@ -6551,34 +6712,37 @@ var OAuthService = class OAuthService2 {
|
|
|
6551
6712
|
return error.message;
|
|
6552
6713
|
return "oauth_provider_error";
|
|
6553
6714
|
}
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6715
|
+
provider(provider) {
|
|
6716
|
+
return provider === "google" ? this.google : this.github;
|
|
6717
|
+
}
|
|
6718
|
+
providerConfig(provider) {
|
|
6719
|
+
const providerConfig = this.config.oauth?.[provider];
|
|
6720
|
+
if (!providerConfig)
|
|
6557
6721
|
throw new OAuthFlowError("oauth_provider_disabled", 404);
|
|
6558
|
-
return
|
|
6722
|
+
return providerConfig;
|
|
6559
6723
|
}
|
|
6560
6724
|
};
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6725
|
+
__decorate39([
|
|
6726
|
+
Inject22(AUTH_CONFIG),
|
|
6727
|
+
__metadata39("design:type", Object)
|
|
6564
6728
|
], OAuthService.prototype, "config", void 0);
|
|
6565
|
-
|
|
6729
|
+
__decorate39([
|
|
6566
6730
|
Log2(),
|
|
6567
|
-
|
|
6731
|
+
__metadata39("design:type", Object)
|
|
6568
6732
|
], OAuthService.prototype, "logger", void 0);
|
|
6569
|
-
OAuthService =
|
|
6570
|
-
|
|
6571
|
-
|
|
6733
|
+
OAuthService = __decorate39([
|
|
6734
|
+
Injectable22(),
|
|
6735
|
+
__metadata39("design:paramtypes", [typeof (_a24 = typeof OAuthStateService !== "undefined" && OAuthStateService) === "function" ? _a24 : Object, typeof (_b14 = typeof GoogleOAuthProvider !== "undefined" && GoogleOAuthProvider) === "function" ? _b14 : Object, typeof (_c10 = typeof GitHubOAuthProvider !== "undefined" && GitHubOAuthProvider) === "function" ? _c10 : Object, typeof (_d8 = typeof OAuthAccountService !== "undefined" && OAuthAccountService) === "function" ? _d8 : Object, typeof (_e5 = typeof AuthSessionService !== "undefined" && AuthSessionService) === "function" ? _e5 : Object, typeof (_f5 = typeof TokenService !== "undefined" && TokenService) === "function" ? _f5 : Object, typeof (_g4 = typeof UserService !== "undefined" && UserService) === "function" ? _g4 : Object, typeof (_h3 = typeof CredentialSetupRequirementService !== "undefined" && CredentialSetupRequirementService) === "function" ? _h3 : Object])
|
|
6572
6736
|
], OAuthService);
|
|
6573
6737
|
|
|
6574
|
-
// src/oauth/
|
|
6575
|
-
var
|
|
6738
|
+
// src/oauth/GitHubOAuthController.ts
|
|
6739
|
+
var __decorate40 = function(decorators, target, key, desc) {
|
|
6576
6740
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6577
6741
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6578
6742
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6579
6743
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6580
6744
|
};
|
|
6581
|
-
var
|
|
6745
|
+
var __metadata40 = function(k, v) {
|
|
6582
6746
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6583
6747
|
};
|
|
6584
6748
|
var __param13 = function(paramIndex, decorator) {
|
|
@@ -6588,63 +6752,141 @@ var __param13 = function(paramIndex, decorator) {
|
|
|
6588
6752
|
};
|
|
6589
6753
|
var _a25;
|
|
6590
6754
|
var callbackKey = /* @__PURE__ */ __name((ctx, { clientIp }) => {
|
|
6591
|
-
const ip = clientIp;
|
|
6592
6755
|
const state = ctx.req.query("state") ?? "none";
|
|
6593
6756
|
const fingerprint = createHash5("sha256").update(state).digest("base64url").slice(0, 24);
|
|
6594
|
-
return `${
|
|
6757
|
+
return `${clientIp}:${fingerprint}`;
|
|
6595
6758
|
}, "callbackKey");
|
|
6596
|
-
var
|
|
6759
|
+
var GitHubOAuthController = class GitHubOAuthController2 {
|
|
6597
6760
|
static {
|
|
6598
|
-
__name(this, "
|
|
6761
|
+
__name(this, "GitHubOAuthController");
|
|
6599
6762
|
}
|
|
6600
6763
|
oauth;
|
|
6601
6764
|
constructor(oauth) {
|
|
6602
6765
|
this.oauth = oauth;
|
|
6603
6766
|
}
|
|
6604
6767
|
start(ctx, returnTo) {
|
|
6605
|
-
return ctx.redirect(this.oauth.
|
|
6768
|
+
return ctx.redirect(this.oauth.startGitHubLogin(returnTo), 302);
|
|
6606
6769
|
}
|
|
6607
6770
|
async callback(ctx, code, state, error) {
|
|
6608
|
-
const redirect = await this.oauth.
|
|
6771
|
+
const redirect = await this.oauth.finishGitHubCallback({ code, state, error });
|
|
6609
6772
|
return ctx.redirect(redirect, 302);
|
|
6610
6773
|
}
|
|
6611
6774
|
link(userId, returnTo) {
|
|
6612
|
-
return this.oauth.
|
|
6775
|
+
return this.oauth.startGitHubLink(userId, returnTo);
|
|
6613
6776
|
}
|
|
6614
6777
|
};
|
|
6615
|
-
|
|
6778
|
+
__decorate40([
|
|
6616
6779
|
Get5("/start"),
|
|
6617
6780
|
RateLimit3({ limit: 20, window: "15m", key: "ip" }),
|
|
6618
6781
|
__param13(0, Ctx2()),
|
|
6619
6782
|
__param13(1, Query2("returnTo")),
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
],
|
|
6624
|
-
|
|
6783
|
+
__metadata40("design:type", Function),
|
|
6784
|
+
__metadata40("design:paramtypes", [Object, String]),
|
|
6785
|
+
__metadata40("design:returntype", void 0)
|
|
6786
|
+
], GitHubOAuthController.prototype, "start", null);
|
|
6787
|
+
__decorate40([
|
|
6625
6788
|
Get5("/callback"),
|
|
6626
6789
|
RateLimit3({ limit: 20, window: "15m", key: callbackKey }),
|
|
6627
6790
|
__param13(0, Ctx2()),
|
|
6628
6791
|
__param13(1, Query2("code")),
|
|
6629
6792
|
__param13(2, Query2("state")),
|
|
6630
6793
|
__param13(3, Query2("error")),
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
],
|
|
6635
|
-
|
|
6794
|
+
__metadata40("design:type", Function),
|
|
6795
|
+
__metadata40("design:paramtypes", [Object, String, String, String]),
|
|
6796
|
+
__metadata40("design:returntype", Promise)
|
|
6797
|
+
], GitHubOAuthController.prototype, "callback", null);
|
|
6798
|
+
__decorate40([
|
|
6636
6799
|
Post6("/link"),
|
|
6637
6800
|
isAuth(),
|
|
6638
6801
|
RateLimit3({ limit: 10, window: "15m", key: "user" }),
|
|
6639
6802
|
__param13(0, User5("id")),
|
|
6640
6803
|
__param13(1, Query2("returnTo")),
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6804
|
+
__metadata40("design:type", Function),
|
|
6805
|
+
__metadata40("design:paramtypes", [String, String]),
|
|
6806
|
+
__metadata40("design:returntype", void 0)
|
|
6807
|
+
], GitHubOAuthController.prototype, "link", null);
|
|
6808
|
+
GitHubOAuthController = __decorate40([
|
|
6809
|
+
Controller6("/auth/oauth/github"),
|
|
6810
|
+
__metadata40("design:paramtypes", [typeof (_a25 = typeof OAuthService !== "undefined" && OAuthService) === "function" ? _a25 : Object])
|
|
6811
|
+
], GitHubOAuthController);
|
|
6812
|
+
|
|
6813
|
+
// src/oauth/OAuthController.ts
|
|
6814
|
+
import { createHash as createHash6 } from "crypto";
|
|
6815
|
+
import { Controller as Controller7, Ctx as Ctx3, Get as Get6, Post as Post7, Query as Query3, User as User6 } from "najm-core";
|
|
6816
|
+
import { RateLimit as RateLimit4 } from "najm-rate";
|
|
6817
|
+
var __decorate41 = function(decorators, target, key, desc) {
|
|
6818
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6819
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6820
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6821
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6822
|
+
};
|
|
6823
|
+
var __metadata41 = function(k, v) {
|
|
6824
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6825
|
+
};
|
|
6826
|
+
var __param14 = function(paramIndex, decorator) {
|
|
6827
|
+
return function(target, key) {
|
|
6828
|
+
decorator(target, key, paramIndex);
|
|
6829
|
+
};
|
|
6830
|
+
};
|
|
6831
|
+
var _a26;
|
|
6832
|
+
var callbackKey2 = /* @__PURE__ */ __name((ctx, { clientIp }) => {
|
|
6833
|
+
const ip = clientIp;
|
|
6834
|
+
const state = ctx.req.query("state") ?? "none";
|
|
6835
|
+
const fingerprint = createHash6("sha256").update(state).digest("base64url").slice(0, 24);
|
|
6836
|
+
return `${ip}:${fingerprint}`;
|
|
6837
|
+
}, "callbackKey");
|
|
6838
|
+
var OAuthController = class OAuthController2 {
|
|
6839
|
+
static {
|
|
6840
|
+
__name(this, "OAuthController");
|
|
6841
|
+
}
|
|
6842
|
+
oauth;
|
|
6843
|
+
constructor(oauth) {
|
|
6844
|
+
this.oauth = oauth;
|
|
6845
|
+
}
|
|
6846
|
+
start(ctx, returnTo) {
|
|
6847
|
+
return ctx.redirect(this.oauth.startGoogleLogin(returnTo), 302);
|
|
6848
|
+
}
|
|
6849
|
+
async callback(ctx, code, state, error) {
|
|
6850
|
+
const redirect = await this.oauth.finishGoogleCallback({ code, state, error });
|
|
6851
|
+
return ctx.redirect(redirect, 302);
|
|
6852
|
+
}
|
|
6853
|
+
link(userId, returnTo) {
|
|
6854
|
+
return this.oauth.startGoogleLink(userId, returnTo);
|
|
6855
|
+
}
|
|
6856
|
+
};
|
|
6857
|
+
__decorate41([
|
|
6858
|
+
Get6("/start"),
|
|
6859
|
+
RateLimit4({ limit: 20, window: "15m", key: "ip" }),
|
|
6860
|
+
__param14(0, Ctx3()),
|
|
6861
|
+
__param14(1, Query3("returnTo")),
|
|
6862
|
+
__metadata41("design:type", Function),
|
|
6863
|
+
__metadata41("design:paramtypes", [Object, String]),
|
|
6864
|
+
__metadata41("design:returntype", void 0)
|
|
6865
|
+
], OAuthController.prototype, "start", null);
|
|
6866
|
+
__decorate41([
|
|
6867
|
+
Get6("/callback"),
|
|
6868
|
+
RateLimit4({ limit: 20, window: "15m", key: callbackKey2 }),
|
|
6869
|
+
__param14(0, Ctx3()),
|
|
6870
|
+
__param14(1, Query3("code")),
|
|
6871
|
+
__param14(2, Query3("state")),
|
|
6872
|
+
__param14(3, Query3("error")),
|
|
6873
|
+
__metadata41("design:type", Function),
|
|
6874
|
+
__metadata41("design:paramtypes", [Object, String, String, String]),
|
|
6875
|
+
__metadata41("design:returntype", Promise)
|
|
6876
|
+
], OAuthController.prototype, "callback", null);
|
|
6877
|
+
__decorate41([
|
|
6878
|
+
Post7("/link"),
|
|
6879
|
+
isAuth(),
|
|
6880
|
+
RateLimit4({ limit: 10, window: "15m", key: "user" }),
|
|
6881
|
+
__param14(0, User6("id")),
|
|
6882
|
+
__param14(1, Query3("returnTo")),
|
|
6883
|
+
__metadata41("design:type", Function),
|
|
6884
|
+
__metadata41("design:paramtypes", [String, String]),
|
|
6885
|
+
__metadata41("design:returntype", void 0)
|
|
6644
6886
|
], OAuthController.prototype, "link", null);
|
|
6645
|
-
OAuthController =
|
|
6646
|
-
|
|
6647
|
-
|
|
6887
|
+
OAuthController = __decorate41([
|
|
6888
|
+
Controller7("/auth/oauth/google"),
|
|
6889
|
+
__metadata41("design:paramtypes", [typeof (_a26 = typeof OAuthService !== "undefined" && OAuthService) === "function" ? _a26 : Object])
|
|
6648
6890
|
], OAuthController);
|
|
6649
6891
|
|
|
6650
6892
|
// src/oauth/index.ts
|
|
@@ -6654,13 +6896,15 @@ var OAUTH_MODULE = [
|
|
|
6654
6896
|
OAuthStateService,
|
|
6655
6897
|
GoogleTokenVerifier,
|
|
6656
6898
|
GoogleOAuthProvider,
|
|
6899
|
+
GitHubOAuthProvider,
|
|
6657
6900
|
OAuthService,
|
|
6658
|
-
OAuthController
|
|
6901
|
+
OAuthController,
|
|
6902
|
+
GitHubOAuthController
|
|
6659
6903
|
];
|
|
6660
6904
|
|
|
6661
6905
|
// src/credentialSetup/CredentialSetupController.ts
|
|
6662
|
-
import { Body as Body7, Controller as
|
|
6663
|
-
import { RateLimit as
|
|
6906
|
+
import { Body as Body7, Controller as Controller8, Get as Get7, Post as Post8, ResMsg as ResMsg6 } from "najm-core";
|
|
6907
|
+
import { RateLimit as RateLimit5 } from "najm-rate";
|
|
6664
6908
|
import { Validate as Validate6 } from "najm-validation";
|
|
6665
6909
|
|
|
6666
6910
|
// src/credentialSetup/CredentialSetupDto.ts
|
|
@@ -6671,21 +6915,21 @@ var credentialSetupChangeDto = z5.object({
|
|
|
6671
6915
|
});
|
|
6672
6916
|
|
|
6673
6917
|
// src/credentialSetup/CredentialSetupController.ts
|
|
6674
|
-
var
|
|
6918
|
+
var __decorate42 = function(decorators, target, key, desc) {
|
|
6675
6919
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6676
6920
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6677
6921
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6678
6922
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6679
6923
|
};
|
|
6680
|
-
var
|
|
6924
|
+
var __metadata42 = function(k, v) {
|
|
6681
6925
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
6682
6926
|
};
|
|
6683
|
-
var
|
|
6927
|
+
var __param15 = function(paramIndex, decorator) {
|
|
6684
6928
|
return function(target, key) {
|
|
6685
6929
|
decorator(target, key, paramIndex);
|
|
6686
6930
|
};
|
|
6687
6931
|
};
|
|
6688
|
-
var
|
|
6932
|
+
var _a27;
|
|
6689
6933
|
var CredentialSetupController = class CredentialSetupController2 {
|
|
6690
6934
|
static {
|
|
6691
6935
|
__name(this, "CredentialSetupController");
|
|
@@ -6704,35 +6948,35 @@ var CredentialSetupController = class CredentialSetupController2 {
|
|
|
6704
6948
|
return this.passwords.cancel();
|
|
6705
6949
|
}
|
|
6706
6950
|
};
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6951
|
+
__decorate42([
|
|
6952
|
+
Get7("/setup"),
|
|
6953
|
+
RateLimit5({ limit: 30, window: "15m", key: "ip" }),
|
|
6710
6954
|
ResMsg6("auth.success.credentialSetupPending"),
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6955
|
+
__metadata42("design:type", Function),
|
|
6956
|
+
__metadata42("design:paramtypes", []),
|
|
6957
|
+
__metadata42("design:returntype", void 0)
|
|
6714
6958
|
], CredentialSetupController.prototype, "status", null);
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6959
|
+
__decorate42([
|
|
6960
|
+
Post8("/change"),
|
|
6961
|
+
RateLimit5({ limit: 5, window: "15m", key: "ip" }),
|
|
6718
6962
|
Validate6(credentialSetupChangeDto),
|
|
6719
6963
|
ResMsg6("auth.success.credentialSetupPasswordReplaced"),
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6964
|
+
__param15(0, Body7()),
|
|
6965
|
+
__metadata42("design:type", Function),
|
|
6966
|
+
__metadata42("design:paramtypes", [Object]),
|
|
6967
|
+
__metadata42("design:returntype", void 0)
|
|
6724
6968
|
], CredentialSetupController.prototype, "change", null);
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6969
|
+
__decorate42([
|
|
6970
|
+
Post8("/cancel"),
|
|
6971
|
+
RateLimit5({ limit: 10, window: "15m", key: "ip" }),
|
|
6728
6972
|
ResMsg6("auth.success.credentialSetupCancelled"),
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6973
|
+
__metadata42("design:type", Function),
|
|
6974
|
+
__metadata42("design:paramtypes", []),
|
|
6975
|
+
__metadata42("design:returntype", void 0)
|
|
6732
6976
|
], CredentialSetupController.prototype, "cancel", null);
|
|
6733
|
-
CredentialSetupController =
|
|
6734
|
-
|
|
6735
|
-
|
|
6977
|
+
CredentialSetupController = __decorate42([
|
|
6978
|
+
Controller8("/auth/credential-setup"),
|
|
6979
|
+
__metadata42("design:paramtypes", [typeof (_a27 = typeof PasswordSetupService !== "undefined" && PasswordSetupService) === "function" ? _a27 : Object])
|
|
6736
6980
|
], CredentialSetupController);
|
|
6737
6981
|
|
|
6738
6982
|
// src/credentialSetup/index.ts
|
|
@@ -6758,6 +7002,19 @@ var validateFrontendPath = /* @__PURE__ */ __name((value, name) => {
|
|
|
6758
7002
|
}
|
|
6759
7003
|
return value;
|
|
6760
7004
|
}, "validateFrontendPath");
|
|
7005
|
+
var validateCallbackUrl = /* @__PURE__ */ __name((value, name) => {
|
|
7006
|
+
let callback;
|
|
7007
|
+
try {
|
|
7008
|
+
callback = new URL(value);
|
|
7009
|
+
} catch {
|
|
7010
|
+
throw new Error(`${name} must be an absolute URL`);
|
|
7011
|
+
}
|
|
7012
|
+
const local = callback.hostname === "localhost" || callback.hostname === "127.0.0.1" || callback.hostname === "[::1]" || callback.hostname === "::1";
|
|
7013
|
+
if (callback.protocol !== "https:" && !(local && callback.protocol === "http:")) {
|
|
7014
|
+
throw new Error(`${name} must use HTTPS (HTTP is allowed only for localhost)`);
|
|
7015
|
+
}
|
|
7016
|
+
return callback.toString();
|
|
7017
|
+
}, "validateCallbackUrl");
|
|
6761
7018
|
var resolveGoogleConfig = /* @__PURE__ */ __name((config) => {
|
|
6762
7019
|
const configuredGoogle = config?.oauth?.google;
|
|
6763
7020
|
if (!configuredGoogle)
|
|
@@ -6771,20 +7028,10 @@ var resolveGoogleConfig = /* @__PURE__ */ __name((config) => {
|
|
|
6771
7028
|
throw Err15.configRequired("auth.oauth.google", "GOOGLE_CLIENT_SECRET");
|
|
6772
7029
|
const frontendUrl = config?.frontendUrl ?? process.env.FRONTEND_URL ?? "http://localhost:3000";
|
|
6773
7030
|
const callbackUrl = google.callbackUrl ?? process.env.GOOGLE_CALLBACK_URL ?? `${frontendUrl.replace(/\/$/, "")}/api/auth/oauth/google/callback`;
|
|
6774
|
-
let callback;
|
|
6775
|
-
try {
|
|
6776
|
-
callback = new URL(callbackUrl);
|
|
6777
|
-
} catch {
|
|
6778
|
-
throw new Error("auth.oauth.google.callbackUrl must be an absolute URL");
|
|
6779
|
-
}
|
|
6780
|
-
const local = callback.hostname === "localhost" || callback.hostname === "127.0.0.1" || callback.hostname === "[::1]" || callback.hostname === "::1";
|
|
6781
|
-
if (callback.protocol !== "https:" && !(local && callback.protocol === "http:")) {
|
|
6782
|
-
throw new Error("auth.oauth.google.callbackUrl must use HTTPS (HTTP is allowed only for localhost)");
|
|
6783
|
-
}
|
|
6784
7031
|
return {
|
|
6785
7032
|
clientId,
|
|
6786
7033
|
clientSecret,
|
|
6787
|
-
callbackUrl:
|
|
7034
|
+
callbackUrl: validateCallbackUrl(callbackUrl, "auth.oauth.google.callbackUrl"),
|
|
6788
7035
|
frontendCallbackPath: validateFrontendPath(google.frontendCallbackPath ?? "/auth/oauth/callback", "auth.oauth.google.frontendCallbackPath"),
|
|
6789
7036
|
errorRedirectPath: validateFrontendPath(google.errorRedirectPath ?? "/login", "auth.oauth.google.errorRedirectPath"),
|
|
6790
7037
|
allowSignup: google.allowSignup ?? true,
|
|
@@ -6792,6 +7039,29 @@ var resolveGoogleConfig = /* @__PURE__ */ __name((config) => {
|
|
|
6792
7039
|
allowedHostedDomains: [...new Set((google.allowedHostedDomains ?? []).map((domain) => domain.trim().toLowerCase()).filter(Boolean))]
|
|
6793
7040
|
};
|
|
6794
7041
|
}, "resolveGoogleConfig");
|
|
7042
|
+
var resolveGitHubConfig = /* @__PURE__ */ __name((config) => {
|
|
7043
|
+
const configuredGitHub = config?.oauth?.github;
|
|
7044
|
+
if (!configuredGitHub)
|
|
7045
|
+
return void 0;
|
|
7046
|
+
const github = configuredGitHub === true ? {} : configuredGitHub;
|
|
7047
|
+
const clientId = github.clientId ?? process.env.GITHUB_CLIENT_ID ?? "";
|
|
7048
|
+
const clientSecret = github.clientSecret ?? process.env.GITHUB_CLIENT_SECRET ?? "";
|
|
7049
|
+
if (!clientId)
|
|
7050
|
+
throw Err15.configRequired("auth.oauth.github", "GITHUB_CLIENT_ID");
|
|
7051
|
+
if (!clientSecret)
|
|
7052
|
+
throw Err15.configRequired("auth.oauth.github", "GITHUB_CLIENT_SECRET");
|
|
7053
|
+
const frontendUrl = config?.frontendUrl ?? process.env.FRONTEND_URL ?? "http://localhost:3000";
|
|
7054
|
+
const callbackUrl = github.callbackUrl ?? process.env.GITHUB_CALLBACK_URL ?? `${frontendUrl.replace(/\/$/, "")}/api/auth/oauth/github/callback`;
|
|
7055
|
+
return {
|
|
7056
|
+
clientId,
|
|
7057
|
+
clientSecret,
|
|
7058
|
+
callbackUrl: validateCallbackUrl(callbackUrl, "auth.oauth.github.callbackUrl"),
|
|
7059
|
+
frontendCallbackPath: validateFrontendPath(github.frontendCallbackPath ?? "/auth/oauth/callback", "auth.oauth.github.frontendCallbackPath"),
|
|
7060
|
+
errorRedirectPath: validateFrontendPath(github.errorRedirectPath ?? "/login", "auth.oauth.github.errorRedirectPath"),
|
|
7061
|
+
allowSignup: github.allowSignup ?? true,
|
|
7062
|
+
autoLinkVerifiedEmail: github.autoLinkVerifiedEmail ?? false
|
|
7063
|
+
};
|
|
7064
|
+
}, "resolveGitHubConfig");
|
|
6795
7065
|
var resolveCredentialSetupConfig = /* @__PURE__ */ __name((config) => {
|
|
6796
7066
|
const password = config?.credentialSetup?.password ?? {};
|
|
6797
7067
|
const ttlMs = password.ttlMs ?? DEFAULT_CREDENTIAL_SETUP_TTL_MS;
|
|
@@ -6842,7 +7112,8 @@ var resolveAuthConfig = /* @__PURE__ */ __name((config) => {
|
|
|
6842
7112
|
},
|
|
6843
7113
|
credentialSetup: resolveCredentialSetupConfig(config),
|
|
6844
7114
|
oauth: {
|
|
6845
|
-
google: resolveGoogleConfig(config)
|
|
7115
|
+
google: resolveGoogleConfig(config),
|
|
7116
|
+
github: resolveGitHubConfig(config)
|
|
6846
7117
|
}
|
|
6847
7118
|
};
|
|
6848
7119
|
if (!finalConfig.jwt.accessSecret) {
|
|
@@ -6855,8 +7126,8 @@ var resolveAuthConfig = /* @__PURE__ */ __name((config) => {
|
|
|
6855
7126
|
}, "resolveAuthConfig");
|
|
6856
7127
|
var selectAuthSchema = /* @__PURE__ */ __name((config) => {
|
|
6857
7128
|
if (config?.schema) {
|
|
6858
|
-
if (config.oauth?.google && !config.schema.oauthAccounts) {
|
|
6859
|
-
throw new Error("auth.schema.oauthAccounts is required when
|
|
7129
|
+
if ((config.oauth?.google || config.oauth?.github) && !config.schema.oauthAccounts) {
|
|
7130
|
+
throw new Error("auth.schema.oauthAccounts is required when OAuth is enabled");
|
|
6860
7131
|
}
|
|
6861
7132
|
if (!config.schema.credentialSetupSessions) {
|
|
6862
7133
|
throw new Error("auth.schema.credentialSetupSessions is required \u2014 re-export it from najm-auth/pg or najm-auth/sqlite");
|