@spfn/auth 0.3.0-beta.7 → 0.3.0-beta.8
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 +378 -0
- package/dist/client-proof.d.ts +23 -12
- package/dist/client-proof.js +143 -4
- package/dist/client-proof.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.js +9 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +76 -3
- package/dist/errors.js +45 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +46 -6
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -1
- package/dist/{authenticate-Mg9D7Nys.d.ts → machine-principals-Bd5hp76H.d.ts} +343 -6
- package/dist/nextjs/api.js +190 -9
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/server.js +59 -8
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +719 -89
- package/dist/server.js +1383 -440
- package/dist/server.js.map +1 -1
- package/migrations/20260901091716_fine_arclight/migration.sql +21 -0
- package/migrations/20260901091716_fine_arclight/snapshot.json +3849 -0
- package/package.json +2 -2
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AuthInitOptions,
|
|
2
|
-
export {
|
|
1
|
+
import { A as AuthInitOptions, o as OAuthProvider, l as VerificationPurpose, j as PermissionCategory, p as AuthContext } from './machine-principals-Bd5hp76H.js';
|
|
2
|
+
export { q as ApproveDeviceAuthParams, r as AuthProfileOutcome, s as AuthProfileVerifier, t as ChangePasswordParams, u as CompleteSignupParams, v as ConfirmSignupLinkParams, C as ConfirmSignupLinkResult, w as DenyDeviceAuthParams, x as DeviceAuthApprovedResult, y as DeviceAuthInfoParams, D as DeviceAuthInfoResult, z as DeviceAuthPendingResult, B as DeviceAuthPollResponseSchema, E as DeviceNameSchema, F as EmailSchema, G as FingerprintSchema, I as IssueOneTimeTokenResult, H as KEY_FINGERPRINT_PREFIX_LENGTH, J as KeyIdSchema, K as KeySummary, M as LoginParams, L as LoginResult, N as LogoutParams, Q as MachinePrincipal, T as MachineVerifierRegistration, W as NativeVerifyOptions, X as NormalizedIdentity, Y as OAuthCallbackParams, Z as OAuthCallbackResult, _ as OAuthCodeExchangeOptions, $ as OAuthNativeParams, f as OAuthNativeResult, a0 as OAuthStartParams, O as OAuthStartResult, a1 as OAuthTokens, a2 as PasswordSchema, a3 as PhoneSchema, a4 as PlatformSchema, a5 as PollDeviceAuthParams, a6 as PollDeviceAuthResult, a7 as PublicKeySchema, a8 as RegisterParams, a9 as RegisterPublicKeyParams, a as RegisterResult, aa as RequestSignupLinkParams, b as RequestSignupLinkResult, ab as RevokeAllKeysParams, e as RevokeAllKeysResult, ac as RevokeKeyParams, ad as RotateKeyParams, d as RotateKeyResult, ae as SendVerificationCodeParams, S as SendVerificationCodeResult, af as StartDeviceAuthParams, c as StartDeviceAuthResult, ag as TargetTypeSchema, ah as UnlinkNotification, ai as UnlinkNotifyRejection, aj as UnlinkNotifyRequest, ak as UnlinkNotifyResult, al as UserCodeSchema, V as VERIFICATION_PURPOSES, k as VERIFICATION_TARGET_TYPES, am as VerificationPurposeSchema, n as VerificationTargetType, an as VerifyCodeParams, ao as VerifyCodeResult, ap as approveDeviceAuthService, m as authRouter, aq as authenticate, ar as buildOAuthErrorUrl, as as changePasswordService, at as completeSignupService, au as confirmSignupLinkService, av as denyDeviceAuthService, aw as getDeviceAuthInfoService, ax as getEnabledOAuthProviders, ay as getGoogleAccessToken, az as getMachinePrincipal, aA as getOAuthProvider, aB as getRegisteredProviders, aC as isOAuthProviderEnabled, aD as isSafeReturnPath, aE as issueOneTimeTokenService, aF as listKeysService, aG as loginService, aH as logoutService, aI as machineAuth, aJ as oauthCallbackService, aK as oauthNativeService, aL as oauthStartService, aM as oauthUnlinkNotifyService, aN as optionalAuth, aO as pollDeviceAuthService, aP as registerAuthProfile, aQ as registerMachineVerifier, aR as registerOAuthProvider, aS as registerPublicKeyService, aT as registerService, aU as requestSignupLinkService, aV as requireEnabledProvider, aW as requireMachineScope, aX as resolveAuthenticatedUser, aY as revokeAllKeysService, aZ as revokeKeyService, a_ as rotateKeyService, a$ as runAuthProfile, b0 as selectAuthProfile, b1 as sendVerificationCodeService, b2 as startDeviceAuthService, b3 as verifyCodeService, b4 as verifyOneTimeTokenService } from './machine-principals-Bd5hp76H.js';
|
|
3
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
4
|
import { K as KeyAlgorithmType, d as InvitationStatus, j as SocialProvider, c as AccountDeletionRequestedBy, i as PurgeStrategy } from './types-DYyhze28.js';
|
|
5
5
|
export { A as ACCOUNT_DELETION_REQUESTED_BY, a as ACCOUNT_DELETION_REQUEST_STATUSES, b as AccountDeletionRequestStatus, I as INVITATION_STATUSES, e as KEY_ALGORITHM, f as KEY_DEVICE_NAME_MAX_LENGTH, g as KEY_PLATFORM, h as KeyPlatformType, P as PURGE_STRATEGIES, S as SOCIAL_PROVIDERS, U as USER_STATUSES, k as UserStatus } from './types-DYyhze28.js';
|
|
@@ -1355,7 +1355,7 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
|
|
|
1355
1355
|
id: number;
|
|
1356
1356
|
name: string;
|
|
1357
1357
|
displayName: string;
|
|
1358
|
-
category: "
|
|
1358
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
|
|
1359
1359
|
}[];
|
|
1360
1360
|
userId: number;
|
|
1361
1361
|
publicId: string;
|
|
@@ -1801,7 +1801,7 @@ declare const accountDeletionRequests: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1801
1801
|
name: string;
|
|
1802
1802
|
tableName: "account_deletion_requests";
|
|
1803
1803
|
dataType: "string enum";
|
|
1804
|
-
data: "
|
|
1804
|
+
data: "admin" | "self";
|
|
1805
1805
|
driverParam: string;
|
|
1806
1806
|
notNull: true;
|
|
1807
1807
|
hasDefault: true;
|
|
@@ -3296,6 +3296,288 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3296
3296
|
type SignupLinkToken = typeof signupLinkTokens.$inferSelect;
|
|
3297
3297
|
type NewSignupLinkToken = typeof signupLinkTokens.$inferInsert;
|
|
3298
3298
|
|
|
3299
|
+
/**
|
|
3300
|
+
* @spfn/auth - Device Authorizations Entity
|
|
3301
|
+
*
|
|
3302
|
+
* Backs device-code login: a device with no key on file yet parks its public key
|
|
3303
|
+
* here, shows a short code, and an already-authenticated device approves it. The
|
|
3304
|
+
* parked key is registered against the approving user's account when the waiting
|
|
3305
|
+
* device polls.
|
|
3306
|
+
*
|
|
3307
|
+
* The pending key material duplicates the `user_public_keys` columns rather than
|
|
3308
|
+
* writing a row there early. A key in `user_public_keys` can sign requests, and
|
|
3309
|
+
* nothing about a row here has been approved yet — one table means "registered"
|
|
3310
|
+
* and the other means "asked to be", and neither is a state of the other.
|
|
3311
|
+
*
|
|
3312
|
+
* Nothing sweeps this table. Rows are judged by `expiresAt` on read, so a stale
|
|
3313
|
+
* row cannot authorize anything; it only keeps its user code out of circulation,
|
|
3314
|
+
* and 31^8 codes do not run out.
|
|
3315
|
+
*/
|
|
3316
|
+
/**
|
|
3317
|
+
* Lifecycle of one device-code request.
|
|
3318
|
+
*
|
|
3319
|
+
* Every transition is one-way and the two terminal states differ: `denied` is a
|
|
3320
|
+
* refusal the waiting device is told about, `consumed` is a completed login that
|
|
3321
|
+
* answers as if it never existed. `pending -> approved -> consumed` is the only
|
|
3322
|
+
* path to a registered key.
|
|
3323
|
+
*
|
|
3324
|
+
* `denied` is also where a global revocation puts a record — a revoke-all, a
|
|
3325
|
+
* password change, a deletion request — including one already approved. The
|
|
3326
|
+
* account has withdrawn it, and what the waiting device is owed for that is the
|
|
3327
|
+
* answer a refusal gives.
|
|
3328
|
+
*/
|
|
3329
|
+
declare const DEVICE_AUTH_STATUSES: readonly ["pending", "approved", "denied", "consumed"];
|
|
3330
|
+
type DeviceAuthStatus = typeof DEVICE_AUTH_STATUSES[number];
|
|
3331
|
+
declare const deviceAuthorizations: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3332
|
+
name: "device_authorizations";
|
|
3333
|
+
schema: string;
|
|
3334
|
+
columns: {
|
|
3335
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3336
|
+
name: string;
|
|
3337
|
+
tableName: "device_authorizations";
|
|
3338
|
+
dataType: "object date";
|
|
3339
|
+
data: Date;
|
|
3340
|
+
driverParam: string;
|
|
3341
|
+
notNull: true;
|
|
3342
|
+
hasDefault: true;
|
|
3343
|
+
isPrimaryKey: false;
|
|
3344
|
+
isAutoincrement: false;
|
|
3345
|
+
hasRuntimeDefault: false;
|
|
3346
|
+
enumValues: undefined;
|
|
3347
|
+
identity: undefined;
|
|
3348
|
+
generated: undefined;
|
|
3349
|
+
}>;
|
|
3350
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
3351
|
+
name: string;
|
|
3352
|
+
tableName: "device_authorizations";
|
|
3353
|
+
dataType: "object date";
|
|
3354
|
+
data: Date;
|
|
3355
|
+
driverParam: string;
|
|
3356
|
+
notNull: true;
|
|
3357
|
+
hasDefault: true;
|
|
3358
|
+
isPrimaryKey: false;
|
|
3359
|
+
isAutoincrement: false;
|
|
3360
|
+
hasRuntimeDefault: false;
|
|
3361
|
+
enumValues: undefined;
|
|
3362
|
+
identity: undefined;
|
|
3363
|
+
generated: undefined;
|
|
3364
|
+
}>;
|
|
3365
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
3366
|
+
name: string;
|
|
3367
|
+
tableName: "device_authorizations";
|
|
3368
|
+
dataType: "number int53";
|
|
3369
|
+
data: number;
|
|
3370
|
+
driverParam: number;
|
|
3371
|
+
notNull: true;
|
|
3372
|
+
hasDefault: true;
|
|
3373
|
+
isPrimaryKey: false;
|
|
3374
|
+
isAutoincrement: false;
|
|
3375
|
+
hasRuntimeDefault: false;
|
|
3376
|
+
enumValues: undefined;
|
|
3377
|
+
identity: undefined;
|
|
3378
|
+
generated: undefined;
|
|
3379
|
+
}>;
|
|
3380
|
+
deviceCodeHash: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3381
|
+
name: string;
|
|
3382
|
+
tableName: "device_authorizations";
|
|
3383
|
+
dataType: "string";
|
|
3384
|
+
data: string;
|
|
3385
|
+
driverParam: string;
|
|
3386
|
+
notNull: true;
|
|
3387
|
+
hasDefault: false;
|
|
3388
|
+
isPrimaryKey: false;
|
|
3389
|
+
isAutoincrement: false;
|
|
3390
|
+
hasRuntimeDefault: false;
|
|
3391
|
+
enumValues: undefined;
|
|
3392
|
+
identity: undefined;
|
|
3393
|
+
generated: undefined;
|
|
3394
|
+
}>;
|
|
3395
|
+
userCode: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3396
|
+
name: string;
|
|
3397
|
+
tableName: "device_authorizations";
|
|
3398
|
+
dataType: "string";
|
|
3399
|
+
data: string;
|
|
3400
|
+
driverParam: string;
|
|
3401
|
+
notNull: true;
|
|
3402
|
+
hasDefault: false;
|
|
3403
|
+
isPrimaryKey: false;
|
|
3404
|
+
isAutoincrement: false;
|
|
3405
|
+
hasRuntimeDefault: false;
|
|
3406
|
+
enumValues: undefined;
|
|
3407
|
+
identity: undefined;
|
|
3408
|
+
generated: undefined;
|
|
3409
|
+
}>;
|
|
3410
|
+
publicKey: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3411
|
+
name: string;
|
|
3412
|
+
tableName: "device_authorizations";
|
|
3413
|
+
dataType: "string";
|
|
3414
|
+
data: string;
|
|
3415
|
+
driverParam: string;
|
|
3416
|
+
notNull: true;
|
|
3417
|
+
hasDefault: false;
|
|
3418
|
+
isPrimaryKey: false;
|
|
3419
|
+
isAutoincrement: false;
|
|
3420
|
+
hasRuntimeDefault: false;
|
|
3421
|
+
enumValues: undefined;
|
|
3422
|
+
identity: undefined;
|
|
3423
|
+
generated: undefined;
|
|
3424
|
+
}>;
|
|
3425
|
+
keyId: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3426
|
+
name: string;
|
|
3427
|
+
tableName: "device_authorizations";
|
|
3428
|
+
dataType: "string";
|
|
3429
|
+
data: string;
|
|
3430
|
+
driverParam: string;
|
|
3431
|
+
notNull: true;
|
|
3432
|
+
hasDefault: false;
|
|
3433
|
+
isPrimaryKey: false;
|
|
3434
|
+
isAutoincrement: false;
|
|
3435
|
+
hasRuntimeDefault: false;
|
|
3436
|
+
enumValues: undefined;
|
|
3437
|
+
identity: undefined;
|
|
3438
|
+
generated: undefined;
|
|
3439
|
+
}>;
|
|
3440
|
+
fingerprint: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3441
|
+
name: string;
|
|
3442
|
+
tableName: "device_authorizations";
|
|
3443
|
+
dataType: "string";
|
|
3444
|
+
data: string;
|
|
3445
|
+
driverParam: string;
|
|
3446
|
+
notNull: true;
|
|
3447
|
+
hasDefault: false;
|
|
3448
|
+
isPrimaryKey: false;
|
|
3449
|
+
isAutoincrement: false;
|
|
3450
|
+
hasRuntimeDefault: false;
|
|
3451
|
+
enumValues: undefined;
|
|
3452
|
+
identity: undefined;
|
|
3453
|
+
generated: undefined;
|
|
3454
|
+
}>;
|
|
3455
|
+
algorithm: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["ES256", "RS256"] & [string, ...string[]]>>>, {
|
|
3456
|
+
name: string;
|
|
3457
|
+
tableName: "device_authorizations";
|
|
3458
|
+
dataType: "string enum";
|
|
3459
|
+
data: "ES256" | "RS256";
|
|
3460
|
+
driverParam: string;
|
|
3461
|
+
notNull: true;
|
|
3462
|
+
hasDefault: true;
|
|
3463
|
+
isPrimaryKey: false;
|
|
3464
|
+
isAutoincrement: false;
|
|
3465
|
+
hasRuntimeDefault: false;
|
|
3466
|
+
enumValues: ["ES256", "RS256"] & [string, ...string[]];
|
|
3467
|
+
identity: undefined;
|
|
3468
|
+
generated: undefined;
|
|
3469
|
+
}>;
|
|
3470
|
+
deviceName: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3471
|
+
name: string;
|
|
3472
|
+
tableName: "device_authorizations";
|
|
3473
|
+
dataType: "string";
|
|
3474
|
+
data: string;
|
|
3475
|
+
driverParam: string;
|
|
3476
|
+
notNull: false;
|
|
3477
|
+
hasDefault: false;
|
|
3478
|
+
isPrimaryKey: false;
|
|
3479
|
+
isAutoincrement: false;
|
|
3480
|
+
hasRuntimeDefault: false;
|
|
3481
|
+
enumValues: undefined;
|
|
3482
|
+
identity: undefined;
|
|
3483
|
+
generated: undefined;
|
|
3484
|
+
}>;
|
|
3485
|
+
platform: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.PgTextBuilder<["ios", "android", "web", "desktop"] & [string, ...string[]]>, {
|
|
3486
|
+
name: string;
|
|
3487
|
+
tableName: "device_authorizations";
|
|
3488
|
+
dataType: "string enum";
|
|
3489
|
+
data: "ios" | "android" | "web" | "desktop";
|
|
3490
|
+
driverParam: string;
|
|
3491
|
+
notNull: false;
|
|
3492
|
+
hasDefault: false;
|
|
3493
|
+
isPrimaryKey: false;
|
|
3494
|
+
isAutoincrement: false;
|
|
3495
|
+
hasRuntimeDefault: false;
|
|
3496
|
+
enumValues: ["ios", "android", "web", "desktop"] & [string, ...string[]];
|
|
3497
|
+
identity: undefined;
|
|
3498
|
+
generated: undefined;
|
|
3499
|
+
}>;
|
|
3500
|
+
status: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["pending", "approved", "denied", "consumed"] & [string, ...string[]]>>>, {
|
|
3501
|
+
name: string;
|
|
3502
|
+
tableName: "device_authorizations";
|
|
3503
|
+
dataType: "string enum";
|
|
3504
|
+
data: "pending" | "approved" | "denied" | "consumed";
|
|
3505
|
+
driverParam: string;
|
|
3506
|
+
notNull: true;
|
|
3507
|
+
hasDefault: true;
|
|
3508
|
+
isPrimaryKey: false;
|
|
3509
|
+
isAutoincrement: false;
|
|
3510
|
+
hasRuntimeDefault: false;
|
|
3511
|
+
enumValues: ["pending", "approved", "denied", "consumed"] & [string, ...string[]];
|
|
3512
|
+
identity: undefined;
|
|
3513
|
+
generated: undefined;
|
|
3514
|
+
}>;
|
|
3515
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.PgBigInt53Builder, {
|
|
3516
|
+
name: string;
|
|
3517
|
+
tableName: "device_authorizations";
|
|
3518
|
+
dataType: "number int53";
|
|
3519
|
+
data: number;
|
|
3520
|
+
driverParam: string | number;
|
|
3521
|
+
notNull: false;
|
|
3522
|
+
hasDefault: false;
|
|
3523
|
+
isPrimaryKey: false;
|
|
3524
|
+
isAutoincrement: false;
|
|
3525
|
+
hasRuntimeDefault: false;
|
|
3526
|
+
enumValues: undefined;
|
|
3527
|
+
identity: undefined;
|
|
3528
|
+
generated: undefined;
|
|
3529
|
+
}>;
|
|
3530
|
+
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
3531
|
+
name: string;
|
|
3532
|
+
tableName: "device_authorizations";
|
|
3533
|
+
dataType: "object date";
|
|
3534
|
+
data: Date;
|
|
3535
|
+
driverParam: string;
|
|
3536
|
+
notNull: true;
|
|
3537
|
+
hasDefault: false;
|
|
3538
|
+
isPrimaryKey: false;
|
|
3539
|
+
isAutoincrement: false;
|
|
3540
|
+
hasRuntimeDefault: false;
|
|
3541
|
+
enumValues: undefined;
|
|
3542
|
+
identity: undefined;
|
|
3543
|
+
generated: undefined;
|
|
3544
|
+
}>;
|
|
3545
|
+
approvedAt: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3546
|
+
name: string;
|
|
3547
|
+
tableName: "device_authorizations";
|
|
3548
|
+
dataType: "object date";
|
|
3549
|
+
data: Date;
|
|
3550
|
+
driverParam: string;
|
|
3551
|
+
notNull: false;
|
|
3552
|
+
hasDefault: false;
|
|
3553
|
+
isPrimaryKey: false;
|
|
3554
|
+
isAutoincrement: false;
|
|
3555
|
+
hasRuntimeDefault: false;
|
|
3556
|
+
enumValues: undefined;
|
|
3557
|
+
identity: undefined;
|
|
3558
|
+
generated: undefined;
|
|
3559
|
+
}>;
|
|
3560
|
+
consumedAt: drizzle_orm_pg_core.PgBuildColumn<"device_authorizations", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3561
|
+
name: string;
|
|
3562
|
+
tableName: "device_authorizations";
|
|
3563
|
+
dataType: "object date";
|
|
3564
|
+
data: Date;
|
|
3565
|
+
driverParam: string;
|
|
3566
|
+
notNull: false;
|
|
3567
|
+
hasDefault: false;
|
|
3568
|
+
isPrimaryKey: false;
|
|
3569
|
+
isAutoincrement: false;
|
|
3570
|
+
hasRuntimeDefault: false;
|
|
3571
|
+
enumValues: undefined;
|
|
3572
|
+
identity: undefined;
|
|
3573
|
+
generated: undefined;
|
|
3574
|
+
}>;
|
|
3575
|
+
};
|
|
3576
|
+
dialect: "pg";
|
|
3577
|
+
}>;
|
|
3578
|
+
type DeviceAuthorization = typeof deviceAuthorizations.$inferSelect;
|
|
3579
|
+
type NewDeviceAuthorization = typeof deviceAuthorizations.$inferInsert;
|
|
3580
|
+
|
|
3299
3581
|
/**
|
|
3300
3582
|
* @spfn/auth - Permissions Entity
|
|
3301
3583
|
*
|
|
@@ -3405,7 +3687,7 @@ declare const permissions: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3405
3687
|
name: string;
|
|
3406
3688
|
tableName: "permissions";
|
|
3407
3689
|
dataType: "string enum";
|
|
3408
|
-
data: "
|
|
3690
|
+
data: "auth" | "custom" | "user" | "rbac" | "system";
|
|
3409
3691
|
driverParam: string;
|
|
3410
3692
|
notNull: false;
|
|
3411
3693
|
hasDefault: false;
|
|
@@ -4027,14 +4309,14 @@ declare class UsersRepository extends BaseRepository {
|
|
|
4027
4309
|
email: string | null;
|
|
4028
4310
|
phone: string | null;
|
|
4029
4311
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
4030
|
-
username: string | null;
|
|
4031
|
-
id: number;
|
|
4032
|
-
createdAt: Date;
|
|
4033
|
-
updatedAt: Date;
|
|
4034
4312
|
publicId: string;
|
|
4035
|
-
passwordHash: string | null;
|
|
4036
4313
|
passwordChangeRequired: boolean;
|
|
4314
|
+
id: number;
|
|
4315
|
+
username: string | null;
|
|
4316
|
+
passwordHash: string | null;
|
|
4037
4317
|
roleId: number;
|
|
4318
|
+
createdAt: Date;
|
|
4319
|
+
updatedAt: Date;
|
|
4038
4320
|
emailVerifiedAt: Date | null;
|
|
4039
4321
|
phoneVerifiedAt: Date | null;
|
|
4040
4322
|
lastLoginAt: Date | null;
|
|
@@ -4187,14 +4469,14 @@ declare class UsersRepository extends BaseRepository {
|
|
|
4187
4469
|
email: string | null;
|
|
4188
4470
|
phone: string | null;
|
|
4189
4471
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
4190
|
-
username: string | null;
|
|
4191
|
-
id: number;
|
|
4192
|
-
createdAt: Date;
|
|
4193
|
-
updatedAt: Date;
|
|
4194
4472
|
publicId: string;
|
|
4195
|
-
passwordHash: string | null;
|
|
4196
4473
|
passwordChangeRequired: boolean;
|
|
4474
|
+
id: number;
|
|
4475
|
+
username: string | null;
|
|
4476
|
+
passwordHash: string | null;
|
|
4197
4477
|
roleId: number;
|
|
4478
|
+
createdAt: Date;
|
|
4479
|
+
updatedAt: Date;
|
|
4198
4480
|
emailVerifiedAt: Date | null;
|
|
4199
4481
|
phoneVerifiedAt: Date | null;
|
|
4200
4482
|
lastLoginAt: Date | null;
|
|
@@ -4219,7 +4501,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
4219
4501
|
id: number;
|
|
4220
4502
|
name: string;
|
|
4221
4503
|
displayName: string;
|
|
4222
|
-
category: "
|
|
4504
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
|
|
4223
4505
|
}[];
|
|
4224
4506
|
}>;
|
|
4225
4507
|
/**
|
|
@@ -4374,23 +4656,23 @@ declare class KeysRepository extends BaseRepository {
|
|
|
4374
4656
|
* Write primary 사용
|
|
4375
4657
|
*/
|
|
4376
4658
|
create(data: NewUserPublicKey): Promise<{
|
|
4377
|
-
userId: number;
|
|
4378
|
-
keyId: string;
|
|
4379
|
-
id: number;
|
|
4380
|
-
isActive: boolean;
|
|
4381
|
-
createdAt: Date;
|
|
4382
4659
|
publicKey: string;
|
|
4383
|
-
|
|
4660
|
+
keyId: string;
|
|
4384
4661
|
fingerprint: string;
|
|
4662
|
+
algorithm: "ES256" | "RS256";
|
|
4385
4663
|
deviceName: string | null;
|
|
4386
4664
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
4665
|
+
userId: number;
|
|
4666
|
+
id: number;
|
|
4667
|
+
isActive: boolean;
|
|
4668
|
+
createdAt: Date;
|
|
4669
|
+
expiresAt: Date | null;
|
|
4670
|
+
revokedAt: Date | null;
|
|
4671
|
+
lastUsedAt: Date | null;
|
|
4387
4672
|
clientKind: "ios" | "android" | "web" | null;
|
|
4388
4673
|
clientVersion: string | null;
|
|
4389
4674
|
clientContractVersion: string | null;
|
|
4390
4675
|
clientSeenAt: Date | null;
|
|
4391
|
-
lastUsedAt: Date | null;
|
|
4392
|
-
expiresAt: Date | null;
|
|
4393
|
-
revokedAt: Date | null;
|
|
4394
4676
|
revokedReason: string | null;
|
|
4395
4677
|
}>;
|
|
4396
4678
|
/**
|
|
@@ -4476,23 +4758,23 @@ declare class KeysRepository extends BaseRepository {
|
|
|
4476
4758
|
* Write primary 사용
|
|
4477
4759
|
*/
|
|
4478
4760
|
deleteByKeyIdAndUserId(keyId: string, userId: number): Promise<{
|
|
4479
|
-
userId: number;
|
|
4480
|
-
keyId: string;
|
|
4481
|
-
id: number;
|
|
4482
|
-
isActive: boolean;
|
|
4483
|
-
createdAt: Date;
|
|
4484
4761
|
publicKey: string;
|
|
4485
|
-
|
|
4762
|
+
keyId: string;
|
|
4486
4763
|
fingerprint: string;
|
|
4764
|
+
algorithm: "ES256" | "RS256";
|
|
4487
4765
|
deviceName: string | null;
|
|
4488
4766
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
4767
|
+
userId: number;
|
|
4768
|
+
id: number;
|
|
4769
|
+
isActive: boolean;
|
|
4770
|
+
createdAt: Date;
|
|
4771
|
+
expiresAt: Date | null;
|
|
4772
|
+
revokedAt: Date | null;
|
|
4773
|
+
lastUsedAt: Date | null;
|
|
4489
4774
|
clientKind: "ios" | "android" | "web" | null;
|
|
4490
4775
|
clientVersion: string | null;
|
|
4491
4776
|
clientContractVersion: string | null;
|
|
4492
4777
|
clientSeenAt: Date | null;
|
|
4493
|
-
lastUsedAt: Date | null;
|
|
4494
|
-
expiresAt: Date | null;
|
|
4495
|
-
revokedAt: Date | null;
|
|
4496
4778
|
revokedReason: string | null;
|
|
4497
4779
|
}>;
|
|
4498
4780
|
/**
|
|
@@ -4680,14 +4962,14 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
4680
4962
|
* Write primary 사용
|
|
4681
4963
|
*/
|
|
4682
4964
|
create(data: NewVerificationCode): Promise<{
|
|
4965
|
+
target: string;
|
|
4966
|
+
targetType: "email" | "phone";
|
|
4967
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
4968
|
+
code: string;
|
|
4683
4969
|
id: number;
|
|
4684
4970
|
createdAt: Date;
|
|
4685
4971
|
updatedAt: Date;
|
|
4686
4972
|
expiresAt: Date;
|
|
4687
|
-
target: string;
|
|
4688
|
-
targetType: "email" | "phone";
|
|
4689
|
-
code: string;
|
|
4690
|
-
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
4691
4973
|
usedAt: Date | null;
|
|
4692
4974
|
attempts: number;
|
|
4693
4975
|
}>;
|
|
@@ -4813,6 +5095,118 @@ declare class SignupLinkTokensRepository extends BaseRepository {
|
|
|
4813
5095
|
}
|
|
4814
5096
|
declare const signupLinkTokensRepository: SignupLinkTokensRepository;
|
|
4815
5097
|
|
|
5098
|
+
/**
|
|
5099
|
+
* Device Authorizations Repository
|
|
5100
|
+
*
|
|
5101
|
+
* Data access for device-code login. Extends BaseRepository for transaction
|
|
5102
|
+
* context detection and read/write splitting.
|
|
5103
|
+
*
|
|
5104
|
+
* Every state change here is a conditional UPDATE naming the exact state it is
|
|
5105
|
+
* allowed to move from, returning the row only when THIS call was the one that
|
|
5106
|
+
* moved it. That is what makes the operations safe to race: two polls on one
|
|
5107
|
+
* approved record, or a deny arriving while an approve is in flight, produce one
|
|
5108
|
+
* winner and one refusal instead of both callers acting on a row they each read
|
|
5109
|
+
* as still theirs to move. Read-then-write would lose that.
|
|
5110
|
+
*
|
|
5111
|
+
* Each of those transitions also carries the TTL, as `now()` evaluated by the
|
|
5112
|
+
* database. The service reads a record before it acts on it, and a record can
|
|
5113
|
+
* pass its expiry in the gap between that read and this UPDATE — an approved one
|
|
5114
|
+
* most of all, since the poll that spends it is the one call that registers a
|
|
5115
|
+
* key. Judging the clock only in the read would let that key be registered after
|
|
5116
|
+
* the code was dead.
|
|
5117
|
+
*/
|
|
5118
|
+
|
|
5119
|
+
declare class DeviceAuthorizationsRepository extends BaseRepository {
|
|
5120
|
+
/**
|
|
5121
|
+
* Insert a pending authorization, unless one of its codes is already taken.
|
|
5122
|
+
*
|
|
5123
|
+
* `onConflictDoNothing` rather than letting the unique index raise: the start
|
|
5124
|
+
* route runs inside a transaction, and a raised unique violation aborts it,
|
|
5125
|
+
* so the retry that a generated-code collision calls for could not run — every
|
|
5126
|
+
* statement after it would fail with "current transaction is aborted" instead.
|
|
5127
|
+
* An empty result is the collision signal, and the caller draws a fresh code.
|
|
5128
|
+
*
|
|
5129
|
+
* Write primary.
|
|
5130
|
+
*
|
|
5131
|
+
* @returns the inserted row, or null if either code collided
|
|
5132
|
+
*/
|
|
5133
|
+
create(data: NewDeviceAuthorization): Promise<DeviceAuthorization | null>;
|
|
5134
|
+
/**
|
|
5135
|
+
* Find a record by its normalized user code, in any state.
|
|
5136
|
+
*
|
|
5137
|
+
* Deliberately unfiltered: which refusal a caller is owed — expired, already
|
|
5138
|
+
* handled, unknown — is the service's decision, and a row filtered out here
|
|
5139
|
+
* would be indistinguishable from a code that was never issued.
|
|
5140
|
+
*
|
|
5141
|
+
* Read replica.
|
|
5142
|
+
*/
|
|
5143
|
+
findByUserCode(userCode: string): Promise<DeviceAuthorization | null>;
|
|
5144
|
+
/**
|
|
5145
|
+
* Find a record by the hash of a device code, in any state.
|
|
5146
|
+
* Unfiltered for the same reason as `findByUserCode`.
|
|
5147
|
+
*
|
|
5148
|
+
* Read replica.
|
|
5149
|
+
*/
|
|
5150
|
+
findByDeviceCodeHash(deviceCodeHash: string): Promise<DeviceAuthorization | null>;
|
|
5151
|
+
/**
|
|
5152
|
+
* Bind the approving user and move the record to `approved`, but only from
|
|
5153
|
+
* `pending`.
|
|
5154
|
+
*
|
|
5155
|
+
* `userId` comes from the approver's authenticated session — never from a
|
|
5156
|
+
* request body — so this is the point where the record gains an owner.
|
|
5157
|
+
*
|
|
5158
|
+
* @returns the updated row, or null if it was no longer pending, or expired
|
|
5159
|
+
*/
|
|
5160
|
+
approve(id: number, userId: number): Promise<DeviceAuthorization | null>;
|
|
5161
|
+
/**
|
|
5162
|
+
* Move the record to `denied`, but only from `pending`.
|
|
5163
|
+
*
|
|
5164
|
+
* No user is bound: a refusal should leave no record of who was asked.
|
|
5165
|
+
*
|
|
5166
|
+
* @returns the updated row, or null if it was no longer pending, or expired
|
|
5167
|
+
*/
|
|
5168
|
+
deny(id: number): Promise<DeviceAuthorization | null>;
|
|
5169
|
+
/**
|
|
5170
|
+
* Refuse every authorization a user still has in flight.
|
|
5171
|
+
*
|
|
5172
|
+
* This is the device-code half of a global revocation. Revoking
|
|
5173
|
+
* `user_public_keys` alone leaves an approved-but-uncollected record behind,
|
|
5174
|
+
* and the next poll on it registers a brand-new active key — so "sign every
|
|
5175
|
+
* device out" would hand one straight back to whoever was still waiting,
|
|
5176
|
+
* which is exactly the person a revoke-all is usually aimed at.
|
|
5177
|
+
*
|
|
5178
|
+
* `denied` rather than a status of its own: a swept record owes its holder
|
|
5179
|
+
* the answer a refused one owes, on all four operations — the waiting device
|
|
5180
|
+
* is told no and stops polling, and info/approve/deny say the request was
|
|
5181
|
+
* already answered. Adding a fourth live status would add a migration and a
|
|
5182
|
+
* case-table row to record a distinction nothing acts on.
|
|
5183
|
+
*
|
|
5184
|
+
* Expired rows are swept too. A global revoke is not the place to reason
|
|
5185
|
+
* about which dead rows were about to die anyway.
|
|
5186
|
+
*
|
|
5187
|
+
* `pending` alongside `approved` even though a pending row carries no
|
|
5188
|
+
* `userId` today, so only approved rows can match: the state list says which
|
|
5189
|
+
* states this is meant to close, and a later change that binds the user
|
|
5190
|
+
* earlier should not silently reopen the hole.
|
|
5191
|
+
*
|
|
5192
|
+
* @returns the rows this call refused
|
|
5193
|
+
*/
|
|
5194
|
+
denyAllActiveByUserId(userId: number): Promise<DeviceAuthorization[]>;
|
|
5195
|
+
/**
|
|
5196
|
+
* Spend an approved record, but only from `approved`, and address it by the
|
|
5197
|
+
* device code hash the caller actually presented.
|
|
5198
|
+
*
|
|
5199
|
+
* This is the one-shot: the winner of two concurrent polls registers the key,
|
|
5200
|
+
* and the loser sees no approved record and is answered as if the code were
|
|
5201
|
+
* unknown. Matching on the hash rather than on an id read a moment ago keeps
|
|
5202
|
+
* the whole decision in one statement.
|
|
5203
|
+
*
|
|
5204
|
+
* @returns the spent row, or null if it was not approved (any more), or expired
|
|
5205
|
+
*/
|
|
5206
|
+
consumeApproved(deviceCodeHash: string): Promise<DeviceAuthorization | null>;
|
|
5207
|
+
}
|
|
5208
|
+
declare const deviceAuthorizationsRepository: DeviceAuthorizationsRepository;
|
|
5209
|
+
|
|
4816
5210
|
/**
|
|
4817
5211
|
* Roles Repository
|
|
4818
5212
|
*
|
|
@@ -4889,8 +5283,8 @@ declare class RolesRepository extends BaseRepository {
|
|
|
4889
5283
|
*/
|
|
4890
5284
|
create(data: NewRoleEntity): Promise<{
|
|
4891
5285
|
description: string | null;
|
|
4892
|
-
id: number;
|
|
4893
5286
|
name: string;
|
|
5287
|
+
id: number;
|
|
4894
5288
|
displayName: string;
|
|
4895
5289
|
isBuiltin: boolean;
|
|
4896
5290
|
isSystem: boolean;
|
|
@@ -4919,8 +5313,8 @@ declare class RolesRepository extends BaseRepository {
|
|
|
4919
5313
|
*/
|
|
4920
5314
|
deleteById(id: number): Promise<{
|
|
4921
5315
|
description: string | null;
|
|
4922
|
-
id: number;
|
|
4923
5316
|
name: string;
|
|
5317
|
+
id: number;
|
|
4924
5318
|
displayName: string;
|
|
4925
5319
|
isBuiltin: boolean;
|
|
4926
5320
|
isSystem: boolean;
|
|
@@ -4953,7 +5347,7 @@ declare class PermissionsRepository extends BaseRepository {
|
|
|
4953
5347
|
name: string;
|
|
4954
5348
|
displayName: string;
|
|
4955
5349
|
description: string | null;
|
|
4956
|
-
category: "
|
|
5350
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | null;
|
|
4957
5351
|
isBuiltin: boolean;
|
|
4958
5352
|
isSystem: boolean;
|
|
4959
5353
|
isActive: boolean;
|
|
@@ -4969,7 +5363,7 @@ declare class PermissionsRepository extends BaseRepository {
|
|
|
4969
5363
|
name: string;
|
|
4970
5364
|
displayName: string;
|
|
4971
5365
|
description: string | null;
|
|
4972
|
-
category: "
|
|
5366
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | null;
|
|
4973
5367
|
isBuiltin: boolean;
|
|
4974
5368
|
isSystem: boolean;
|
|
4975
5369
|
isActive: boolean;
|
|
@@ -5009,7 +5403,7 @@ declare class PermissionsRepository extends BaseRepository {
|
|
|
5009
5403
|
name: string;
|
|
5010
5404
|
displayName: string;
|
|
5011
5405
|
description: string | null;
|
|
5012
|
-
category: "
|
|
5406
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | null;
|
|
5013
5407
|
isBuiltin: boolean;
|
|
5014
5408
|
isSystem: boolean;
|
|
5015
5409
|
isActive: boolean;
|
|
@@ -5020,16 +5414,16 @@ declare class PermissionsRepository extends BaseRepository {
|
|
|
5020
5414
|
*/
|
|
5021
5415
|
deleteById(id: number): Promise<{
|
|
5022
5416
|
description: string | null;
|
|
5023
|
-
|
|
5417
|
+
metadata: Record<string, any> | null;
|
|
5024
5418
|
name: string;
|
|
5419
|
+
id: number;
|
|
5025
5420
|
displayName: string;
|
|
5026
5421
|
isBuiltin: boolean;
|
|
5027
5422
|
isSystem: boolean;
|
|
5028
5423
|
isActive: boolean;
|
|
5029
5424
|
createdAt: Date;
|
|
5030
5425
|
updatedAt: Date;
|
|
5031
|
-
|
|
5032
|
-
category: "custom" | "user" | "auth" | "rbac" | "system" | null;
|
|
5426
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | null;
|
|
5033
5427
|
}>;
|
|
5034
5428
|
}
|
|
5035
5429
|
declare const permissionsRepository: PermissionsRepository;
|
|
@@ -5074,9 +5468,9 @@ declare class RolePermissionsRepository extends BaseRepository {
|
|
|
5074
5468
|
*/
|
|
5075
5469
|
createMany(data: NewRolePermission[]): Promise<{
|
|
5076
5470
|
id: number;
|
|
5471
|
+
roleId: number;
|
|
5077
5472
|
createdAt: Date;
|
|
5078
5473
|
updatedAt: Date;
|
|
5079
|
-
roleId: number;
|
|
5080
5474
|
permissionId: number;
|
|
5081
5475
|
}[]>;
|
|
5082
5476
|
/**
|
|
@@ -5092,9 +5486,9 @@ declare class RolePermissionsRepository extends BaseRepository {
|
|
|
5092
5486
|
*/
|
|
5093
5487
|
setPermissionsForRole(roleId: number, permissionIds: number[]): Promise<{
|
|
5094
5488
|
id: number;
|
|
5489
|
+
roleId: number;
|
|
5095
5490
|
createdAt: Date;
|
|
5096
5491
|
updatedAt: Date;
|
|
5097
|
-
roleId: number;
|
|
5098
5492
|
permissionId: number;
|
|
5099
5493
|
}[]>;
|
|
5100
5494
|
}
|
|
@@ -5159,9 +5553,9 @@ declare class UserPermissionsRepository extends BaseRepository {
|
|
|
5159
5553
|
id: number;
|
|
5160
5554
|
createdAt: Date;
|
|
5161
5555
|
updatedAt: Date;
|
|
5162
|
-
expiresAt: Date | null;
|
|
5163
|
-
reason: string | null;
|
|
5164
5556
|
permissionId: number;
|
|
5557
|
+
reason: string | null;
|
|
5558
|
+
expiresAt: Date | null;
|
|
5165
5559
|
granted: boolean;
|
|
5166
5560
|
}>;
|
|
5167
5561
|
/**
|
|
@@ -5185,9 +5579,9 @@ declare class UserPermissionsRepository extends BaseRepository {
|
|
|
5185
5579
|
id: number;
|
|
5186
5580
|
createdAt: Date;
|
|
5187
5581
|
updatedAt: Date;
|
|
5188
|
-
expiresAt: Date | null;
|
|
5189
|
-
reason: string | null;
|
|
5190
5582
|
permissionId: number;
|
|
5583
|
+
reason: string | null;
|
|
5584
|
+
expiresAt: Date | null;
|
|
5191
5585
|
granted: boolean;
|
|
5192
5586
|
}>;
|
|
5193
5587
|
/**
|
|
@@ -5266,6 +5660,7 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5266
5660
|
* 프로필 생성
|
|
5267
5661
|
*/
|
|
5268
5662
|
create(data: NewUserProfile): Promise<{
|
|
5663
|
+
metadata: Record<string, any> | null;
|
|
5269
5664
|
userId: number;
|
|
5270
5665
|
id: number;
|
|
5271
5666
|
displayName: string | null;
|
|
@@ -5283,7 +5678,6 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5283
5678
|
location: string | null;
|
|
5284
5679
|
company: string | null;
|
|
5285
5680
|
jobTitle: string | null;
|
|
5286
|
-
metadata: Record<string, any> | null;
|
|
5287
5681
|
}>;
|
|
5288
5682
|
/**
|
|
5289
5683
|
* 프로필 업데이트 (by ID)
|
|
@@ -5335,6 +5729,7 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5335
5729
|
* 프로필 삭제 (by ID)
|
|
5336
5730
|
*/
|
|
5337
5731
|
deleteById(id: number): Promise<{
|
|
5732
|
+
metadata: Record<string, any> | null;
|
|
5338
5733
|
userId: number;
|
|
5339
5734
|
id: number;
|
|
5340
5735
|
displayName: string | null;
|
|
@@ -5352,12 +5747,12 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5352
5747
|
location: string | null;
|
|
5353
5748
|
company: string | null;
|
|
5354
5749
|
jobTitle: string | null;
|
|
5355
|
-
metadata: Record<string, any> | null;
|
|
5356
5750
|
}>;
|
|
5357
5751
|
/**
|
|
5358
5752
|
* 프로필 삭제 (by User ID)
|
|
5359
5753
|
*/
|
|
5360
5754
|
deleteByUserId(userId: number): Promise<{
|
|
5755
|
+
metadata: Record<string, any> | null;
|
|
5361
5756
|
userId: number;
|
|
5362
5757
|
id: number;
|
|
5363
5758
|
displayName: string | null;
|
|
@@ -5375,7 +5770,6 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5375
5770
|
location: string | null;
|
|
5376
5771
|
company: string | null;
|
|
5377
5772
|
jobTitle: string | null;
|
|
5378
|
-
metadata: Record<string, any> | null;
|
|
5379
5773
|
}>;
|
|
5380
5774
|
/**
|
|
5381
5775
|
* 프로필 Upsert (by User ID)
|
|
@@ -5384,6 +5778,7 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5384
5778
|
* 새로 생성 시 displayName은 필수 (없으면 'User'로 설정)
|
|
5385
5779
|
*/
|
|
5386
5780
|
upsertByUserId(userId: number, data: Partial<Omit<NewUserProfile, 'userId'>>): Promise<{
|
|
5781
|
+
metadata: Record<string, any> | null;
|
|
5387
5782
|
userId: number;
|
|
5388
5783
|
id: number;
|
|
5389
5784
|
displayName: string | null;
|
|
@@ -5401,7 +5796,6 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
5401
5796
|
location: string | null;
|
|
5402
5797
|
company: string | null;
|
|
5403
5798
|
jobTitle: string | null;
|
|
5404
|
-
metadata: Record<string, any> | null;
|
|
5405
5799
|
}>;
|
|
5406
5800
|
/**
|
|
5407
5801
|
* User ID로 프로필 데이터 조회 (formatted)
|
|
@@ -5529,15 +5923,15 @@ declare class InvitationsRepository extends BaseRepository {
|
|
|
5529
5923
|
*/
|
|
5530
5924
|
create(data: NewInvitation): Promise<{
|
|
5531
5925
|
email: string;
|
|
5926
|
+
metadata: Record<string, any> | null;
|
|
5927
|
+
token: string;
|
|
5532
5928
|
status: "pending" | "accepted" | "expired" | "cancelled";
|
|
5533
5929
|
id: number;
|
|
5930
|
+
roleId: number;
|
|
5534
5931
|
createdAt: Date;
|
|
5535
5932
|
updatedAt: Date;
|
|
5536
|
-
roleId: number;
|
|
5537
|
-
metadata: Record<string, any> | null;
|
|
5538
|
-
expiresAt: Date;
|
|
5539
|
-
token: string;
|
|
5540
5933
|
invitedBy: number;
|
|
5934
|
+
expiresAt: Date;
|
|
5541
5935
|
acceptedAt: Date | null;
|
|
5542
5936
|
cancelledAt: Date | null;
|
|
5543
5937
|
}>;
|
|
@@ -5563,15 +5957,15 @@ declare class InvitationsRepository extends BaseRepository {
|
|
|
5563
5957
|
*/
|
|
5564
5958
|
deleteById(id: number): Promise<{
|
|
5565
5959
|
email: string;
|
|
5960
|
+
metadata: Record<string, any> | null;
|
|
5961
|
+
token: string;
|
|
5566
5962
|
status: "pending" | "accepted" | "expired" | "cancelled";
|
|
5567
5963
|
id: number;
|
|
5964
|
+
roleId: number;
|
|
5568
5965
|
createdAt: Date;
|
|
5569
5966
|
updatedAt: Date;
|
|
5570
|
-
roleId: number;
|
|
5571
|
-
metadata: Record<string, any> | null;
|
|
5572
|
-
expiresAt: Date;
|
|
5573
|
-
token: string;
|
|
5574
5967
|
invitedBy: number;
|
|
5968
|
+
expiresAt: Date;
|
|
5575
5969
|
acceptedAt: Date | null;
|
|
5576
5970
|
cancelledAt: Date | null;
|
|
5577
5971
|
}>;
|
|
@@ -5809,9 +6203,9 @@ declare class SocialAccountsRepository extends BaseRepository {
|
|
|
5809
6203
|
createdAt: Date;
|
|
5810
6204
|
updatedAt: Date;
|
|
5811
6205
|
provider: "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
6206
|
+
accessToken: string | null;
|
|
5812
6207
|
providerUserId: string;
|
|
5813
6208
|
providerEmail: string | null;
|
|
5814
|
-
accessToken: string | null;
|
|
5815
6209
|
refreshToken: string | null;
|
|
5816
6210
|
tokenExpiresAt: Date | null;
|
|
5817
6211
|
}>;
|
|
@@ -5825,9 +6219,9 @@ declare class SocialAccountsRepository extends BaseRepository {
|
|
|
5825
6219
|
createdAt: Date;
|
|
5826
6220
|
updatedAt: Date;
|
|
5827
6221
|
provider: "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
6222
|
+
accessToken: string | null;
|
|
5828
6223
|
providerUserId: string;
|
|
5829
6224
|
providerEmail: string | null;
|
|
5830
|
-
accessToken: string | null;
|
|
5831
6225
|
refreshToken: string | null;
|
|
5832
6226
|
tokenExpiresAt: Date | null;
|
|
5833
6227
|
}>;
|
|
@@ -5887,7 +6281,7 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
5887
6281
|
requestedAt: Date;
|
|
5888
6282
|
purgeScheduledAt: Date;
|
|
5889
6283
|
status: "pending" | "cancelled" | "completed";
|
|
5890
|
-
requestedBy: "
|
|
6284
|
+
requestedBy: "admin" | "self";
|
|
5891
6285
|
reason: string | null;
|
|
5892
6286
|
cancelledAt: Date | null;
|
|
5893
6287
|
completedAt: Date | null;
|
|
@@ -5906,7 +6300,7 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
5906
6300
|
requestedAt: Date;
|
|
5907
6301
|
purgeScheduledAt: Date;
|
|
5908
6302
|
status: "pending" | "cancelled" | "completed";
|
|
5909
|
-
requestedBy: "
|
|
6303
|
+
requestedBy: "admin" | "self";
|
|
5910
6304
|
reason: string | null;
|
|
5911
6305
|
cancelledAt: Date | null;
|
|
5912
6306
|
completedAt: Date | null;
|
|
@@ -5928,7 +6322,7 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
5928
6322
|
requestedAt: Date;
|
|
5929
6323
|
purgeScheduledAt: Date;
|
|
5930
6324
|
status: "pending" | "cancelled" | "completed";
|
|
5931
|
-
requestedBy: "
|
|
6325
|
+
requestedBy: "admin" | "self";
|
|
5932
6326
|
reason: string | null;
|
|
5933
6327
|
cancelledAt: Date | null;
|
|
5934
6328
|
completedAt: Date | null;
|
|
@@ -5947,7 +6341,7 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
5947
6341
|
requestedAt: Date;
|
|
5948
6342
|
purgeScheduledAt: Date;
|
|
5949
6343
|
status: "pending" | "cancelled" | "completed";
|
|
5950
|
-
requestedBy: "
|
|
6344
|
+
requestedBy: "admin" | "self";
|
|
5951
6345
|
reason: string | null;
|
|
5952
6346
|
cancelledAt: Date | null;
|
|
5953
6347
|
completedAt: Date | null;
|
|
@@ -5958,18 +6352,18 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
5958
6352
|
* Write primary 사용
|
|
5959
6353
|
*/
|
|
5960
6354
|
create(data: NewAccountDeletionRequest): Promise<{
|
|
5961
|
-
userId: number | null;
|
|
5962
6355
|
status: "pending" | "cancelled" | "completed";
|
|
5963
|
-
|
|
6356
|
+
userId: number | null;
|
|
5964
6357
|
id: number;
|
|
5965
6358
|
createdAt: Date;
|
|
5966
6359
|
updatedAt: Date;
|
|
5967
|
-
|
|
6360
|
+
reason: string | null;
|
|
6361
|
+
purgeScheduledAt: Date;
|
|
5968
6362
|
cancelledAt: Date | null;
|
|
6363
|
+
completedAt: Date | null;
|
|
5969
6364
|
userPublicId: string;
|
|
5970
6365
|
requestedAt: Date;
|
|
5971
|
-
requestedBy: "
|
|
5972
|
-
reason: string | null;
|
|
6366
|
+
requestedBy: "admin" | "self";
|
|
5973
6367
|
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5974
6368
|
}>;
|
|
5975
6369
|
/**
|
|
@@ -5989,7 +6383,7 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
5989
6383
|
requestedAt: Date;
|
|
5990
6384
|
purgeScheduledAt: Date;
|
|
5991
6385
|
status: "pending" | "cancelled" | "completed";
|
|
5992
|
-
requestedBy: "
|
|
6386
|
+
requestedBy: "admin" | "self";
|
|
5993
6387
|
reason: string | null;
|
|
5994
6388
|
cancelledAt: Date | null;
|
|
5995
6389
|
completedAt: Date | null;
|
|
@@ -6014,7 +6408,7 @@ declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
|
6014
6408
|
requestedAt: Date;
|
|
6015
6409
|
purgeScheduledAt: Date;
|
|
6016
6410
|
status: "pending" | "cancelled" | "completed";
|
|
6017
|
-
requestedBy: "
|
|
6411
|
+
requestedBy: "admin" | "self";
|
|
6018
6412
|
reason: string | null;
|
|
6019
6413
|
cancelledAt: Date | null;
|
|
6020
6414
|
completedAt: Date | null;
|
|
@@ -6553,14 +6947,14 @@ declare function getUser(c: Context | {
|
|
|
6553
6947
|
email: string | null;
|
|
6554
6948
|
phone: string | null;
|
|
6555
6949
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
6556
|
-
username: string | null;
|
|
6557
|
-
id: number;
|
|
6558
|
-
createdAt: Date;
|
|
6559
|
-
updatedAt: Date;
|
|
6560
6950
|
publicId: string;
|
|
6561
|
-
passwordHash: string | null;
|
|
6562
6951
|
passwordChangeRequired: boolean;
|
|
6952
|
+
id: number;
|
|
6953
|
+
username: string | null;
|
|
6954
|
+
passwordHash: string | null;
|
|
6563
6955
|
roleId: number;
|
|
6956
|
+
createdAt: Date;
|
|
6957
|
+
updatedAt: Date;
|
|
6564
6958
|
emailVerifiedAt: Date | null;
|
|
6565
6959
|
phoneVerifiedAt: Date | null;
|
|
6566
6960
|
lastLoginAt: Date | null;
|
|
@@ -6651,6 +7045,8 @@ declare const COOKIE_NAMES: {
|
|
|
6651
7045
|
readonly OAUTH_CSRF: string;
|
|
6652
7046
|
/** Password-setup session for verified-email signup — temporary, single-purpose */
|
|
6653
7047
|
readonly SIGNUP_SETUP: string;
|
|
7048
|
+
/** CSRF token — the only cookie here the browser can read */
|
|
7049
|
+
readonly CSRF: string;
|
|
6654
7050
|
};
|
|
6655
7051
|
/**
|
|
6656
7052
|
* OAuth CSRF 쿠키를 PORT 접미사와 무관하게 전부 수집한다.
|
|
@@ -6712,6 +7108,36 @@ interface BeforeRegisterContext {
|
|
|
6712
7108
|
/** App-supplied registration metadata (register params / OAuth start params / invitation) */
|
|
6713
7109
|
metadata?: Record<string, unknown>;
|
|
6714
7110
|
}
|
|
7111
|
+
/**
|
|
7112
|
+
* How the Next.js proxy treats a cookie-authenticated mutation that arrives
|
|
7113
|
+
* without a valid CSRF header.
|
|
7114
|
+
*
|
|
7115
|
+
* - `off`: no check
|
|
7116
|
+
* - `warn`: allow it through, log one line per request that would be refused
|
|
7117
|
+
* - `enforce`: refuse it with 403
|
|
7118
|
+
*/
|
|
7119
|
+
type CsrfMode = 'off' | 'warn' | 'enforce';
|
|
7120
|
+
/**
|
|
7121
|
+
* CSRF configuration for the Next.js proxy
|
|
7122
|
+
*/
|
|
7123
|
+
interface AuthCsrfConfig {
|
|
7124
|
+
/**
|
|
7125
|
+
* @default 'warn' — an existing app gets signal before it gets breakage.
|
|
7126
|
+
* `SPFN_AUTH_CSRF` sets it when this is not; new apps scaffolded by
|
|
7127
|
+
* `spfn init` are given `enforce`.
|
|
7128
|
+
*/
|
|
7129
|
+
mode?: CsrfMode;
|
|
7130
|
+
/**
|
|
7131
|
+
* Backend paths that skip the check, matched exactly.
|
|
7132
|
+
*
|
|
7133
|
+
* These are route paths as the backend sees them (`/webhooks/stripe`), not
|
|
7134
|
+
* `/api/rpc/...` URLs, with route params already substituted. Intended for
|
|
7135
|
+
* endpoints a browser session never calls — webhook receivers and the like.
|
|
7136
|
+
* A path listed here is unprotected for cookie callers too, so list only
|
|
7137
|
+
* endpoints that carry their own authentication.
|
|
7138
|
+
*/
|
|
7139
|
+
exemptPaths?: string[];
|
|
7140
|
+
}
|
|
6715
7141
|
/**
|
|
6716
7142
|
* Auth configuration
|
|
6717
7143
|
*/
|
|
@@ -6755,6 +7181,17 @@ interface AuthConfig {
|
|
|
6755
7181
|
* ```
|
|
6756
7182
|
*/
|
|
6757
7183
|
beforeRegister?: (context: BeforeRegisterContext) => void | Promise<void>;
|
|
7184
|
+
/**
|
|
7185
|
+
* CSRF protection for cookie-session mutations, enforced in the Next.js proxy.
|
|
7186
|
+
*
|
|
7187
|
+
* @example
|
|
7188
|
+
* ```typescript
|
|
7189
|
+
* configureAuth({
|
|
7190
|
+
* csrf: { mode: 'enforce', exemptPaths: ['/webhooks/stripe'] },
|
|
7191
|
+
* });
|
|
7192
|
+
* ```
|
|
7193
|
+
*/
|
|
7194
|
+
csrf?: AuthCsrfConfig;
|
|
6758
7195
|
}
|
|
6759
7196
|
/**
|
|
6760
7197
|
* Configure global auth settings
|
|
@@ -6796,6 +7233,64 @@ declare function runBeforeRegister(context: BeforeRegisterContext): Promise<void
|
|
|
6796
7233
|
* 4. Default (7 days)
|
|
6797
7234
|
*/
|
|
6798
7235
|
declare function getSessionTtl(override?: string | number): number;
|
|
7236
|
+
/**
|
|
7237
|
+
* Get the CSRF mode
|
|
7238
|
+
*
|
|
7239
|
+
* Priority:
|
|
7240
|
+
* 1. Global config (configureAuth)
|
|
7241
|
+
* 2. Environment variable (SPFN_AUTH_CSRF)
|
|
7242
|
+
* 3. Default ('warn')
|
|
7243
|
+
*
|
|
7244
|
+
* An unrecognized value is a typo in the one setting that turns the check on;
|
|
7245
|
+
* it resolves to `enforce` and says so, rather than quietly leaving mutations
|
|
7246
|
+
* unprotected. It says so once per process: this runs on every mutation, so a
|
|
7247
|
+
* per-call error would be pure repetition burying the rest of the log.
|
|
7248
|
+
*/
|
|
7249
|
+
declare function getCsrfMode(): CsrfMode;
|
|
7250
|
+
/**
|
|
7251
|
+
* Get the paths exempted from the CSRF check (exact match, backend route paths)
|
|
7252
|
+
*/
|
|
7253
|
+
declare function getCsrfExemptPaths(): string[];
|
|
7254
|
+
|
|
7255
|
+
/**
|
|
7256
|
+
* @spfn/auth - CSRF token derivation
|
|
7257
|
+
*
|
|
7258
|
+
* The token is an HMAC of the session's key id under a subkey derived from the
|
|
7259
|
+
* session secret. Two properties follow from that shape:
|
|
7260
|
+
*
|
|
7261
|
+
* - The proxy recomputes it from the session it just unsealed, so a value an
|
|
7262
|
+
* attacker planted in the readable cookie (sibling-subdomain cookie tossing)
|
|
7263
|
+
* never verifies. Nothing here compares a cookie against a header.
|
|
7264
|
+
* - It is bound to the key id, so rotating the session key invalidates it.
|
|
7265
|
+
*
|
|
7266
|
+
* No new secret: the subkey is a labelled HMAC of SPFN_AUTH_SESSION_SECRET, so
|
|
7267
|
+
* the key that encrypts sessions is never used verbatim as the token key.
|
|
7268
|
+
*/
|
|
7269
|
+
/** Header the readable CSRF cookie is mirrored into by the client. */
|
|
7270
|
+
declare const CSRF_HEADER = "x-spfn-csrf";
|
|
7271
|
+
/**
|
|
7272
|
+
* Derive the CSRF token for a session key id.
|
|
7273
|
+
*
|
|
7274
|
+
* @param keyId - Session key id (`SessionData.keyId`)
|
|
7275
|
+
* @returns 64-char hex token — safe to put in a readable cookie, it reveals
|
|
7276
|
+
* neither the secret nor the key id
|
|
7277
|
+
*/
|
|
7278
|
+
declare function deriveCsrfToken(keyId: string): Promise<string>;
|
|
7279
|
+
/**
|
|
7280
|
+
* Whether a presented header value carries the expected token.
|
|
7281
|
+
*
|
|
7282
|
+
* The header may carry several comma-separated candidates — a browser sees every
|
|
7283
|
+
* `spfn_csrf*` cookie set on the host and cannot tell which dev instance owns
|
|
7284
|
+
* which, nor which of two same-named cookies a sibling subdomain tossed in.
|
|
7285
|
+
*
|
|
7286
|
+
* Every candidate the client is allowed to send is checked — the cap here is the
|
|
7287
|
+
* one it selects against — so a genuine value is never evicted by tossed ones
|
|
7288
|
+
* that happen to sort ahead of it. A header longer than that can only come from a
|
|
7289
|
+
* client that ignored the shared bound, and its surplus is dropped. Accepting any
|
|
7290
|
+
* match is no weaker than accepting one: a candidate the attacker chose still has
|
|
7291
|
+
* to equal a value recomputed from the session.
|
|
7292
|
+
*/
|
|
7293
|
+
declare function matchesCsrfToken(expected: string, presented: string | null | undefined): boolean;
|
|
6799
7294
|
|
|
6800
7295
|
/**
|
|
6801
7296
|
* One-Time Token Manager
|
|
@@ -6898,6 +7393,107 @@ declare function configureDeletion(options?: Partial<AuthDeletionConfig>): void;
|
|
|
6898
7393
|
*/
|
|
6899
7394
|
declare function getDeletionConfig(): AuthDeletionConfig;
|
|
6900
7395
|
|
|
7396
|
+
/**
|
|
7397
|
+
* Device-code Login Configuration
|
|
7398
|
+
*
|
|
7399
|
+
* Singleton config for device-code login, mirroring `lib/deletion-config.ts`: a
|
|
7400
|
+
* mutable module-level value, set once during `createAuthLifecycle()` and read at
|
|
7401
|
+
* request time.
|
|
7402
|
+
*
|
|
7403
|
+
* Both knobs are answers the server hands to a client that cannot ask again — the
|
|
7404
|
+
* waiting device is told its expiry and its poll interval in the `start` response
|
|
7405
|
+
* and then just obeys them — so they have to be resolved before any request is
|
|
7406
|
+
* served, not read from an environment variable at each use.
|
|
7407
|
+
*/
|
|
7408
|
+
interface AuthDeviceAuthConfig {
|
|
7409
|
+
/** How long a device code stays usable, in milliseconds. */
|
|
7410
|
+
ttlMs: number;
|
|
7411
|
+
/** How long the waiting device should wait between polls, in milliseconds. */
|
|
7412
|
+
intervalMs: number;
|
|
7413
|
+
}
|
|
7414
|
+
/**
|
|
7415
|
+
* Ten minutes. Long enough to walk to the other device and type the code, short
|
|
7416
|
+
* enough that a code glimpsed over a shoulder is worthless soon after.
|
|
7417
|
+
*/
|
|
7418
|
+
declare const DEFAULT_DEVICE_AUTH_TTL_MS: number;
|
|
7419
|
+
/** Five seconds. The interval the server asks for; the rate limit is what enforces it. */
|
|
7420
|
+
declare const DEFAULT_DEVICE_AUTH_INTERVAL_MS: number;
|
|
7421
|
+
/**
|
|
7422
|
+
* Set the resolved device-auth config. Called synchronously from
|
|
7423
|
+
* `createAuthLifecycle()` for the same reason `configureDeletion` is: it must
|
|
7424
|
+
* take effect before any handler that reads `getDeviceAuthConfig()` can run.
|
|
7425
|
+
*
|
|
7426
|
+
* Both knobs are whole millisecond counts, and one that is not is refused here
|
|
7427
|
+
* rather than served. `intervalMs` is the reason the check exists: it leaves as
|
|
7428
|
+
* `intervalMillis` in the start and poll answers, which `DeviceAuthPollResponseSchema`
|
|
7429
|
+
* declares an integer and the mobile contract exports as one, so a fractional
|
|
7430
|
+
* value configured here would reach a generated client as a number its decoder
|
|
7431
|
+
* refuses — at the one moment the flow depends on that client asking again.
|
|
7432
|
+
*/
|
|
7433
|
+
declare function configureDeviceAuth(options?: Partial<AuthDeviceAuthConfig>): void;
|
|
7434
|
+
/**
|
|
7435
|
+
* Read the current device-auth config. Safe to call any time — defaults apply
|
|
7436
|
+
* even if `createAuthLifecycle()` was never given a `deviceAuth` block.
|
|
7437
|
+
*/
|
|
7438
|
+
declare function getDeviceAuthConfig(): AuthDeviceAuthConfig;
|
|
7439
|
+
|
|
7440
|
+
/**
|
|
7441
|
+
* @spfn/auth - Device code generation
|
|
7442
|
+
*
|
|
7443
|
+
* The two codes device-code login runs on, and the one-way function between the
|
|
7444
|
+
* device code and what is stored for it.
|
|
7445
|
+
*
|
|
7446
|
+
* They are different kinds of value and are treated differently everywhere. The
|
|
7447
|
+
* device code is a credential: the polling device holds it, nothing else proves
|
|
7448
|
+
* who that device is, so it is long, random, and stored only as a hash. The user
|
|
7449
|
+
* code is read off one screen and typed on another, so it is short and stored in
|
|
7450
|
+
* the clear — it authorizes nothing on its own, since only an already
|
|
7451
|
+
* authenticated caller can act on it.
|
|
7452
|
+
*/
|
|
7453
|
+
/**
|
|
7454
|
+
* Alphabet the user code is drawn from.
|
|
7455
|
+
*
|
|
7456
|
+
* 0/O and 1/I/L are the pairs a person mistypes when copying a code between two
|
|
7457
|
+
* screens, so neither member of either pair is in the set. 31 characters over 8
|
|
7458
|
+
* positions is ~2^39 codes, which the per-IP and per-account rate limits on
|
|
7459
|
+
* every route that accepts one make unguessable in the ten minutes a code lives.
|
|
7460
|
+
*/
|
|
7461
|
+
declare const USER_CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
7462
|
+
/** Characters in a user code, not counting the dash it is displayed with. */
|
|
7463
|
+
declare const USER_CODE_LENGTH = 8;
|
|
7464
|
+
/**
|
|
7465
|
+
* A fresh user code in stored form — uppercase, no dash.
|
|
7466
|
+
*
|
|
7467
|
+
* `randomInt` rather than `Math.random`: this is drawn from the same CSPRNG the
|
|
7468
|
+
* device code is, and a predictable user code lets an attacker have a victim
|
|
7469
|
+
* approve a code the attacker is polling.
|
|
7470
|
+
*/
|
|
7471
|
+
declare function generateUserCode(): string;
|
|
7472
|
+
/** The stored form as a person reads it: `XXXX-XXXX`. */
|
|
7473
|
+
declare function formatUserCode(userCode: string): string;
|
|
7474
|
+
/**
|
|
7475
|
+
* Fold a typed user code back to the stored form.
|
|
7476
|
+
*
|
|
7477
|
+
* Someone reading `WXYZ-2345` off a screen types the dash, or spaces, or lower
|
|
7478
|
+
* case. All of those name the same code, so all of them have to reach the same
|
|
7479
|
+
* lookup — the alternative is a code that is on screen and still refused.
|
|
7480
|
+
*
|
|
7481
|
+
* Only the user code is normalized. The device code is a credential and is
|
|
7482
|
+
* matched byte for byte: accepting variant spellings of a credential is how one
|
|
7483
|
+
* token becomes several strings and a one-shot record is used twice.
|
|
7484
|
+
*/
|
|
7485
|
+
declare function normalizeUserCode(input: string): string;
|
|
7486
|
+
/** A fresh device code, returned to the new device once and never stored. */
|
|
7487
|
+
declare function generateDeviceCode(): string;
|
|
7488
|
+
/**
|
|
7489
|
+
* What the row holds instead of the device code.
|
|
7490
|
+
*
|
|
7491
|
+
* Unsalted SHA-256, as with the ops-token and signup-link secrets: the input is
|
|
7492
|
+
* 256 bits of CSPRNG output, so there is no dictionary to defend against and a
|
|
7493
|
+
* per-row salt would only stop the exact-match lookup this has to support.
|
|
7494
|
+
*/
|
|
7495
|
+
declare function hashDeviceCode(deviceCode: string): string;
|
|
7496
|
+
|
|
6901
7497
|
/**
|
|
6902
7498
|
* @spfn/auth - Centralized Logger
|
|
6903
7499
|
*
|
|
@@ -6911,6 +7507,7 @@ declare const authLogger: {
|
|
|
6911
7507
|
login: _spfn_core_logger.Logger;
|
|
6912
7508
|
keyRotation: _spfn_core_logger.Logger;
|
|
6913
7509
|
oauth: _spfn_core_logger.Logger;
|
|
7510
|
+
csrf: _spfn_core_logger.Logger;
|
|
6914
7511
|
};
|
|
6915
7512
|
session: _spfn_core_logger.Logger;
|
|
6916
7513
|
service: _spfn_core_logger.Logger;
|
|
@@ -7103,6 +7700,38 @@ interface AuthLifecycleOptions extends AuthInitOptions {
|
|
|
7103
7700
|
*/
|
|
7104
7701
|
onBeforePurge?: (user: AccountDeletionPurgeUser) => Promise<void>;
|
|
7105
7702
|
};
|
|
7703
|
+
/**
|
|
7704
|
+
* Device-code login configuration
|
|
7705
|
+
*
|
|
7706
|
+
* Controls the codes handed out by `POST /_auth/device/start` and obeyed by
|
|
7707
|
+
* `POST /_auth/device/poll`. Both values are announced to the waiting device
|
|
7708
|
+
* in the start response, so they are resolved here rather than read per call,
|
|
7709
|
+
* and both must be a positive whole number of milliseconds — the interval is
|
|
7710
|
+
* published as an integer and a fraction is refused at startup rather than
|
|
7711
|
+
* handed to a client that cannot decode it.
|
|
7712
|
+
*
|
|
7713
|
+
* @example
|
|
7714
|
+
* ```typescript
|
|
7715
|
+
* createAuthLifecycle({
|
|
7716
|
+
* deviceAuth: {
|
|
7717
|
+
* ttlMs: 5 * 60 * 1000, // a code lives 5 minutes
|
|
7718
|
+
* intervalMs: 3000, // poll every 3 seconds
|
|
7719
|
+
* },
|
|
7720
|
+
* })
|
|
7721
|
+
* ```
|
|
7722
|
+
*/
|
|
7723
|
+
deviceAuth?: {
|
|
7724
|
+
/**
|
|
7725
|
+
* How long a device code stays usable, in milliseconds.
|
|
7726
|
+
* @default 600000 (10 minutes)
|
|
7727
|
+
*/
|
|
7728
|
+
ttlMs?: number;
|
|
7729
|
+
/**
|
|
7730
|
+
* Poll interval the server asks the waiting device to keep, in milliseconds.
|
|
7731
|
+
* @default 5000
|
|
7732
|
+
*/
|
|
7733
|
+
intervalMs?: number;
|
|
7734
|
+
};
|
|
7106
7735
|
}
|
|
7107
7736
|
declare function createAuthLifecycle(options?: AuthLifecycleOptions): AuthLifecycleConfig;
|
|
7108
7737
|
|
|
@@ -7181,6 +7810,7 @@ declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TL
|
|
|
7181
7810
|
* 발행 시점:
|
|
7182
7811
|
* - 이메일/전화 로그인 성공 시
|
|
7183
7812
|
* - OAuth 기존 사용자 로그인 시
|
|
7813
|
+
* - 기기 코드 승인이 소비되어 새 기기 키가 등록될 때 (provider: 'device')
|
|
7184
7814
|
*
|
|
7185
7815
|
* @example
|
|
7186
7816
|
* ```typescript
|
|
@@ -7193,7 +7823,7 @@ declare const authLoginEvent: _spfn_core_event.EventDef<{
|
|
|
7193
7823
|
email?: string | undefined;
|
|
7194
7824
|
phone?: string | undefined;
|
|
7195
7825
|
userId: string;
|
|
7196
|
-
provider: "google" | "apple" | "github" | "kakao" | "naver" | "superself" | "
|
|
7826
|
+
provider: "email" | "phone" | "google" | "apple" | "github" | "kakao" | "naver" | "superself" | "device";
|
|
7197
7827
|
}>;
|
|
7198
7828
|
/**
|
|
7199
7829
|
* auth.register - 회원가입 성공 이벤트
|
|
@@ -7216,7 +7846,7 @@ declare const authRegisterEvent: _spfn_core_event.EventDef<{
|
|
|
7216
7846
|
[x: string]: unknown;
|
|
7217
7847
|
} | undefined;
|
|
7218
7848
|
userId: string;
|
|
7219
|
-
provider: "
|
|
7849
|
+
provider: "email" | "phone" | "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
7220
7850
|
}>;
|
|
7221
7851
|
/**
|
|
7222
7852
|
* auth.invitation.created - 초대 생성 이벤트
|
|
@@ -7243,10 +7873,10 @@ declare const invitationCreatedEvent: _spfn_core_event.EventDef<{
|
|
|
7243
7873
|
[x: string]: unknown;
|
|
7244
7874
|
} | undefined;
|
|
7245
7875
|
email: string;
|
|
7246
|
-
roleId: number;
|
|
7247
|
-
expiresAt: string;
|
|
7248
7876
|
token: string;
|
|
7877
|
+
roleId: number;
|
|
7249
7878
|
invitedBy: string;
|
|
7879
|
+
expiresAt: string;
|
|
7250
7880
|
invitationId: string;
|
|
7251
7881
|
isResend: boolean;
|
|
7252
7882
|
}>;
|
|
@@ -7290,7 +7920,7 @@ declare const authDeletionRequestedEvent: _spfn_core_event.EventDef<{
|
|
|
7290
7920
|
userId: string;
|
|
7291
7921
|
purgeScheduledAt: string;
|
|
7292
7922
|
userPublicId: string;
|
|
7293
|
-
requestedBy: "
|
|
7923
|
+
requestedBy: "admin" | "self";
|
|
7294
7924
|
}>;
|
|
7295
7925
|
/**
|
|
7296
7926
|
* auth.deletion.cancelled - 계정 탈퇴 복구 이벤트
|
|
@@ -7335,7 +7965,7 @@ declare const authDeletionCompletedEvent: _spfn_core_event.EventDef<{
|
|
|
7335
7965
|
declare const oauthUnlinkedEvent: _spfn_core_event.EventDef<{
|
|
7336
7966
|
reason?: string | undefined;
|
|
7337
7967
|
userId: string;
|
|
7338
|
-
provider: "
|
|
7968
|
+
provider: "email" | "phone" | "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
7339
7969
|
providerUserId: string;
|
|
7340
7970
|
}>;
|
|
7341
7971
|
/**
|
|
@@ -7350,4 +7980,4 @@ type AuthDeletionCancelledPayload = typeof authDeletionCancelledEvent._payload;
|
|
|
7350
7980
|
type AuthDeletionCompletedPayload = typeof authDeletionCompletedEvent._payload;
|
|
7351
7981
|
type OAuthUnlinkedPayload = typeof oauthUnlinkedEvent._payload;
|
|
7352
7982
|
|
|
7353
|
-
export { type AccountDeletionPurgeUser, type AccountDeletionRequest, AccountDeletionRequestedBy, AccountDeletionRequestsRepository, type AuthConfig, AuthContext, type AuthDeletionCancelledPayload, type AuthDeletionCompletedPayload, type AuthDeletionConfig, type AuthDeletionRequestedPayload, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, type BeforeRegisterContext, COOKIE_NAMES, type CancelAccountDeletionParams, type CancelAccountDeletionResult, type CreateOAuthStateParams, DEFAULT_DELETION_ALLOW_SELF_IMMEDIATE, DEFAULT_DELETION_GRACE_PERIOD_DAYS, DEFAULT_DELETION_PURGE_CRON, DEFAULT_DELETION_PURGE_STRATEGY, DEFAULT_DELETION_SEND_NOTIFICATIONS, type DecryptedOAuthToken, type EmailNormalizationResult, EnvironmentKeyringTokenCipher, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, type IssuedOpsToken, KeyAlgorithmType, KeysRepository, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewInvitation, type NewOpsToken, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewSignupLinkToken, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, OAuthProvider, type OAuthState, type OAuthTokenCipher, type OAuthTokenContext, type OAuthTokenType, type OAuthUnlinkedPayload, type OpsToken, OpsTokensRepository, type PendingDeletionInfo, type Permission, type PermissionEntity, PermissionsRepository, PurgeStrategy, type PurgeUserResult, type RegisterChannel, type RequestAccountDeletionParams, type RequestAccountDeletionResult, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionPayload, type SignupLinkToken, SignupLinkTokensRepository, SocialAccountsRepository, SocialProvider, type SweepDuePurgesResult, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, type VerifiedOpsToken, type VerifyIdTokenParams, acceptInvitation, accountDeletionRequests, accountDeletionRequestsRepository, addPermissionToRole, appleProvider, assertCanAssignRole, authDeletionCancelledEvent, authDeletionCompletedEvent, authDeletionRequestedEvent, authJobRouter, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelAccountDeletionService, cancelInvitation, checkUsernameAvailableService, configureAuth, configureDeletion, configureOAuthTokenCipher, createAuthDeletionJobRouter, createAuthDeletionPurgeJob, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, decryptToken, deleteInvitation, deleteRole, encryptToken, exchangeCodeForTokens, expireOldInvitations, generateOAuthNonce, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getDeletionConfig, getDummyPasswordHash, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getLocale, getOneTimeTokenManager, getOpsToken, getOptionalAuth, getPendingDeletionInfo, getRole, getRoleByName, getRolePermissions, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, githubProvider, googleProvider, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initOneTimeTokenManager, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isEncrypted, isGoogleOAuthEnabled, issueOpsTokenService, kakaoProvider, keysRepository, listInvitations, listOpsTokensService, matchOAuthCsrfCookies, naverProvider, normalizeEmail, normalizeOptionalEmail, normalizeStoredEmails, oauthUnlinkedEvent, oneTimeTokenAuth, opsTokenAuth, opsTokens, opsTokensRepository, parseDuration, permissions, permissionsRepository, purgeUserService, refreshAccessToken, removePermissionFromRole, requestAccountDeletionService, requireAnyPermission, requireOpsScope, requirePermissions, requireRole, resendInvitation, revokeOpsTokenService, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, runBeforeRegister, setRolePermissions, signupLinkTokens, signupLinkTokensRepository, socialAccountsRepository, sweepDuePurges, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyIdToken, verifyKeyFingerprint, verifyOAuthState, verifyOpsTokenService, verifyPassword, verifyToken };
|
|
7983
|
+
export { type AccountDeletionPurgeUser, type AccountDeletionRequest, AccountDeletionRequestedBy, AccountDeletionRequestsRepository, type AuthConfig, AuthContext, type AuthCsrfConfig, type AuthDeletionCancelledPayload, type AuthDeletionCompletedPayload, type AuthDeletionConfig, type AuthDeletionRequestedPayload, type AuthDeviceAuthConfig, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, type BeforeRegisterContext, COOKIE_NAMES, CSRF_HEADER, type CancelAccountDeletionParams, type CancelAccountDeletionResult, type CreateOAuthStateParams, type CsrfMode, DEFAULT_DELETION_ALLOW_SELF_IMMEDIATE, DEFAULT_DELETION_GRACE_PERIOD_DAYS, DEFAULT_DELETION_PURGE_CRON, DEFAULT_DELETION_PURGE_STRATEGY, DEFAULT_DELETION_SEND_NOTIFICATIONS, DEFAULT_DEVICE_AUTH_INTERVAL_MS, DEFAULT_DEVICE_AUTH_TTL_MS, DEVICE_AUTH_STATUSES, type DecryptedOAuthToken, type DeviceAuthStatus, type DeviceAuthorization, DeviceAuthorizationsRepository, type EmailNormalizationResult, EnvironmentKeyringTokenCipher, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, type IssuedOpsToken, KeyAlgorithmType, KeysRepository, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewDeviceAuthorization, type NewInvitation, type NewOpsToken, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewSignupLinkToken, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, OAuthProvider, type OAuthState, type OAuthTokenCipher, type OAuthTokenContext, type OAuthTokenType, type OAuthUnlinkedPayload, type OpsToken, OpsTokensRepository, type PendingDeletionInfo, type Permission, type PermissionEntity, PermissionsRepository, PurgeStrategy, type PurgeUserResult, type RegisterChannel, type RequestAccountDeletionParams, type RequestAccountDeletionResult, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionPayload, type SignupLinkToken, SignupLinkTokensRepository, SocialAccountsRepository, SocialProvider, type SweepDuePurgesResult, type TokenPayload, USER_CODE_ALPHABET, USER_CODE_LENGTH, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, type VerifiedOpsToken, type VerifyIdTokenParams, acceptInvitation, accountDeletionRequests, accountDeletionRequestsRepository, addPermissionToRole, appleProvider, assertCanAssignRole, authDeletionCancelledEvent, authDeletionCompletedEvent, authDeletionRequestedEvent, authJobRouter, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelAccountDeletionService, cancelInvitation, checkUsernameAvailableService, configureAuth, configureDeletion, configureDeviceAuth, configureOAuthTokenCipher, createAuthDeletionJobRouter, createAuthDeletionPurgeJob, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, decryptToken, deleteInvitation, deleteRole, deriveCsrfToken, deviceAuthorizations, deviceAuthorizationsRepository, encryptToken, exchangeCodeForTokens, expireOldInvitations, formatUserCode, generateDeviceCode, generateOAuthNonce, generateToken, generateUserCode, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getCsrfExemptPaths, getCsrfMode, getDeletionConfig, getDeviceAuthConfig, getDummyPasswordHash, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getLocale, getOneTimeTokenManager, getOpsToken, getOptionalAuth, getPendingDeletionInfo, getRole, getRoleByName, getRolePermissions, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, githubProvider, googleProvider, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashDeviceCode, hashPassword, initOneTimeTokenManager, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isEncrypted, isGoogleOAuthEnabled, issueOpsTokenService, kakaoProvider, keysRepository, listInvitations, listOpsTokensService, matchOAuthCsrfCookies, matchesCsrfToken, naverProvider, normalizeEmail, normalizeOptionalEmail, normalizeStoredEmails, normalizeUserCode, oauthUnlinkedEvent, oneTimeTokenAuth, opsTokenAuth, opsTokens, opsTokensRepository, parseDuration, permissions, permissionsRepository, purgeUserService, refreshAccessToken, removePermissionFromRole, requestAccountDeletionService, requireAnyPermission, requireOpsScope, requirePermissions, requireRole, resendInvitation, revokeOpsTokenService, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, runBeforeRegister, setRolePermissions, signupLinkTokens, signupLinkTokensRepository, socialAccountsRepository, sweepDuePurges, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyIdToken, verifyKeyFingerprint, verifyOAuthState, verifyOpsTokenService, verifyPassword, verifyToken };
|