@h-ai/iam 0.1.0-alpha.18 → 0.1.0-alpha.20
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 +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +227 -81
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1364,7 +1364,7 @@ interface IamFunctions {
|
|
|
1364
1364
|
* 关闭后访问 `iam.auth` 等属性将返回未初始化错误。
|
|
1365
1365
|
*/
|
|
1366
1366
|
close: () => Promise<void>;
|
|
1367
|
-
/**
|
|
1367
|
+
/** 当前脱敏后的配置快照(未初始化时为 null) */
|
|
1368
1368
|
readonly config: IamConfig | null;
|
|
1369
1369
|
/** 是否已初始化 */
|
|
1370
1370
|
readonly isInitialized: boolean;
|
package/dist/index.js
CHANGED
|
@@ -663,18 +663,18 @@ var API_KEY_FIELDS = [
|
|
|
663
663
|
}
|
|
664
664
|
];
|
|
665
665
|
var apiKeyRepoInstance = null;
|
|
666
|
-
var
|
|
666
|
+
var apiKeyRepoSqlOps = null;
|
|
667
667
|
function resetApiKeyRepoSingleton() {
|
|
668
668
|
apiKeyRepoInstance = null;
|
|
669
|
-
|
|
669
|
+
apiKeyRepoSqlOps = null;
|
|
670
670
|
}
|
|
671
671
|
async function createDbApiKeyRepository() {
|
|
672
|
-
if (apiKeyRepoInstance &&
|
|
672
|
+
if (apiKeyRepoInstance && apiKeyRepoSqlOps === reldb.sql)
|
|
673
673
|
return apiKeyRepoInstance;
|
|
674
674
|
const repo = new DbApiKeyRepository();
|
|
675
675
|
await repo.count();
|
|
676
676
|
apiKeyRepoInstance = repo;
|
|
677
|
-
|
|
677
|
+
apiKeyRepoSqlOps = reldb.sql;
|
|
678
678
|
return repo;
|
|
679
679
|
}
|
|
680
680
|
var DbApiKeyRepository = class extends BaseReldbCrudRepository {
|
|
@@ -753,6 +753,20 @@ var DbApiKeyRepository = class extends BaseReldbCrudRepository {
|
|
|
753
753
|
);
|
|
754
754
|
}
|
|
755
755
|
};
|
|
756
|
+
|
|
757
|
+
// src/iam-agreement.ts
|
|
758
|
+
function buildAgreementDisplay(config, enabled) {
|
|
759
|
+
if (!enabled)
|
|
760
|
+
return void 0;
|
|
761
|
+
if (!config.userAgreementUrl && !config.privacyPolicyUrl)
|
|
762
|
+
return void 0;
|
|
763
|
+
return {
|
|
764
|
+
userAgreementUrl: config.userAgreementUrl,
|
|
765
|
+
privacyPolicyUrl: config.privacyPolicyUrl,
|
|
766
|
+
showOnRegister: config.showOnRegister,
|
|
767
|
+
showOnLogin: config.showOnLogin
|
|
768
|
+
};
|
|
769
|
+
}
|
|
756
770
|
var TABLE_NAME2 = "hai_iam_users";
|
|
757
771
|
var USER_FIELDS = [
|
|
758
772
|
{
|
|
@@ -893,18 +907,18 @@ var USER_FIELDS = [
|
|
|
893
907
|
}
|
|
894
908
|
];
|
|
895
909
|
var userRepoInstance = null;
|
|
896
|
-
var
|
|
910
|
+
var userRepoSqlOps = null;
|
|
897
911
|
function resetUserRepoSingleton() {
|
|
898
912
|
userRepoInstance = null;
|
|
899
|
-
|
|
913
|
+
userRepoSqlOps = null;
|
|
900
914
|
}
|
|
901
915
|
async function createDbUserRepository() {
|
|
902
|
-
if (userRepoInstance &&
|
|
916
|
+
if (userRepoInstance && userRepoSqlOps === reldb.sql)
|
|
903
917
|
return userRepoInstance;
|
|
904
918
|
const repo = new DbUserRepository();
|
|
905
919
|
await repo.count();
|
|
906
920
|
userRepoInstance = repo;
|
|
907
|
-
|
|
921
|
+
userRepoSqlOps = reldb.sql;
|
|
908
922
|
return repo;
|
|
909
923
|
}
|
|
910
924
|
var DbUserRepository = class extends BaseReldbCrudRepository {
|
|
@@ -1503,9 +1517,6 @@ function createOtpStrategy(config) {
|
|
|
1503
1517
|
const registerConfig = config.registerConfig;
|
|
1504
1518
|
const allowAutoRegister = registerConfig?.enabled ?? config.autoRegister ?? false;
|
|
1505
1519
|
const defaultEnabled = registerConfig?.defaultEnabled ?? true;
|
|
1506
|
-
function buildChallengeResult(expiresAt) {
|
|
1507
|
-
return { expiresAt };
|
|
1508
|
-
}
|
|
1509
1520
|
const strategy = {
|
|
1510
1521
|
type: "otp",
|
|
1511
1522
|
name: "otp-strategy",
|
|
@@ -1633,7 +1644,7 @@ function createOtpStrategy(config) {
|
|
|
1633
1644
|
iamM("iam_identifierTypeNotSupported")
|
|
1634
1645
|
);
|
|
1635
1646
|
}
|
|
1636
|
-
const result =
|
|
1647
|
+
const result = { expiresAt };
|
|
1637
1648
|
logger3.debug("OTP challenge sent", { identifier, expiresAt });
|
|
1638
1649
|
return ok(result);
|
|
1639
1650
|
}
|
|
@@ -1870,20 +1881,6 @@ function buildAuthnOperations(deps) {
|
|
|
1870
1881
|
} = deps;
|
|
1871
1882
|
const loginConfig = LoginConfigSchema.parse(config.login ?? {});
|
|
1872
1883
|
const agreementConfig = AgreementConfigSchema.parse(config.agreements ?? {});
|
|
1873
|
-
function buildAgreementDisplay() {
|
|
1874
|
-
if (!agreementConfig.showOnLogin) {
|
|
1875
|
-
return void 0;
|
|
1876
|
-
}
|
|
1877
|
-
if (!agreementConfig.userAgreementUrl && !agreementConfig.privacyPolicyUrl) {
|
|
1878
|
-
return void 0;
|
|
1879
|
-
}
|
|
1880
|
-
return {
|
|
1881
|
-
userAgreementUrl: agreementConfig.userAgreementUrl,
|
|
1882
|
-
privacyPolicyUrl: agreementConfig.privacyPolicyUrl,
|
|
1883
|
-
showOnRegister: agreementConfig.showOnRegister,
|
|
1884
|
-
showOnLogin: agreementConfig.showOnLogin
|
|
1885
|
-
};
|
|
1886
|
-
}
|
|
1887
1884
|
function loginDisabled(type) {
|
|
1888
1885
|
if (!loginConfig[type]) {
|
|
1889
1886
|
return err(
|
|
@@ -1960,7 +1957,7 @@ function buildAuthnOperations(deps) {
|
|
|
1960
1957
|
tokens: tokenPair,
|
|
1961
1958
|
roles: roleCodesResult.data,
|
|
1962
1959
|
permissions: permCodesResult.data,
|
|
1963
|
-
agreements: buildAgreementDisplay()
|
|
1960
|
+
agreements: buildAgreementDisplay(agreementConfig, agreementConfig.showOnLogin)
|
|
1964
1961
|
});
|
|
1965
1962
|
}
|
|
1966
1963
|
async function loginWithStrategy(type, credentials, strategy) {
|
|
@@ -2103,18 +2100,18 @@ var PERMISSION_FIELDS = [
|
|
|
2103
2100
|
}
|
|
2104
2101
|
];
|
|
2105
2102
|
var permRepoInstance = null;
|
|
2106
|
-
var
|
|
2103
|
+
var permRepoSqlOps = null;
|
|
2107
2104
|
function resetPermissionRepoSingleton() {
|
|
2108
2105
|
permRepoInstance = null;
|
|
2109
|
-
|
|
2106
|
+
permRepoSqlOps = null;
|
|
2110
2107
|
}
|
|
2111
2108
|
async function createDbPermissionRepository() {
|
|
2112
|
-
if (permRepoInstance &&
|
|
2109
|
+
if (permRepoInstance && permRepoSqlOps === reldb.sql)
|
|
2113
2110
|
return permRepoInstance;
|
|
2114
2111
|
const repo = new DbPermissionRepository();
|
|
2115
2112
|
await repo.count();
|
|
2116
2113
|
permRepoInstance = repo;
|
|
2117
|
-
|
|
2114
|
+
permRepoSqlOps = reldb.sql;
|
|
2118
2115
|
return repo;
|
|
2119
2116
|
}
|
|
2120
2117
|
var DbPermissionRepository = class extends BaseReldbCrudRepository {
|
|
@@ -2619,18 +2616,18 @@ var ROLE_FIELDS = [
|
|
|
2619
2616
|
}
|
|
2620
2617
|
];
|
|
2621
2618
|
var roleRepoInstance = null;
|
|
2622
|
-
var
|
|
2619
|
+
var roleRepoSqlOps = null;
|
|
2623
2620
|
function resetRoleRepoSingleton() {
|
|
2624
2621
|
roleRepoInstance = null;
|
|
2625
|
-
|
|
2622
|
+
roleRepoSqlOps = null;
|
|
2626
2623
|
}
|
|
2627
2624
|
async function createDbRoleRepository() {
|
|
2628
|
-
if (roleRepoInstance &&
|
|
2625
|
+
if (roleRepoInstance && roleRepoSqlOps === reldb.sql)
|
|
2629
2626
|
return roleRepoInstance;
|
|
2630
2627
|
const repo = new DbRoleRepository();
|
|
2631
2628
|
await repo.count();
|
|
2632
2629
|
roleRepoInstance = repo;
|
|
2633
|
-
|
|
2630
|
+
roleRepoSqlOps = reldb.sql;
|
|
2634
2631
|
return repo;
|
|
2635
2632
|
}
|
|
2636
2633
|
var DbRoleRepository = class extends BaseReldbCrudRepository {
|
|
@@ -3561,6 +3558,13 @@ function restoreSessionDates(session) {
|
|
|
3561
3558
|
expiresAt: session.expiresAt instanceof Date ? session.expiresAt : new Date(session.expiresAt)
|
|
3562
3559
|
};
|
|
3563
3560
|
}
|
|
3561
|
+
function buildRepositoryError(messageKey, message, cause) {
|
|
3562
|
+
return err(
|
|
3563
|
+
HaiIamError.REPOSITORY_ERROR,
|
|
3564
|
+
iamM(messageKey, { params: { message } }),
|
|
3565
|
+
cause
|
|
3566
|
+
);
|
|
3567
|
+
}
|
|
3564
3568
|
function createCacheSessionRepository(sessionMaxAge, refreshTokenMaxAge) {
|
|
3565
3569
|
const repo = {
|
|
3566
3570
|
async save(session, tokenPair) {
|
|
@@ -3639,31 +3643,82 @@ function createCacheSessionRepository(sessionMaxAge, refreshTokenMaxAge) {
|
|
|
3639
3643
|
return ok(void 0);
|
|
3640
3644
|
},
|
|
3641
3645
|
async removeByAccessToken(accessToken) {
|
|
3642
|
-
const
|
|
3643
|
-
|
|
3646
|
+
const tokenKey = buildTokenKey(accessToken);
|
|
3647
|
+
const sessionResult = await cache.kv.get(tokenKey);
|
|
3648
|
+
if (!sessionResult.success) {
|
|
3649
|
+
return buildRepositoryError(
|
|
3650
|
+
"iam_querySessionMappingCacheFailed",
|
|
3651
|
+
sessionResult.error.message,
|
|
3652
|
+
sessionResult.error
|
|
3653
|
+
);
|
|
3654
|
+
}
|
|
3655
|
+
if (sessionResult.data) {
|
|
3644
3656
|
const session = sessionResult.data;
|
|
3645
|
-
await cache.set_.srem(buildUserTokensKey(session.userId), accessToken);
|
|
3657
|
+
const removeUserTokenResult = await cache.set_.srem(buildUserTokensKey(session.userId), accessToken);
|
|
3658
|
+
if (!removeUserTokenResult.success) {
|
|
3659
|
+
return buildRepositoryError(
|
|
3660
|
+
"iam_deleteUserSessionCacheFailed",
|
|
3661
|
+
removeUserTokenResult.error.message,
|
|
3662
|
+
removeUserTokenResult.error
|
|
3663
|
+
);
|
|
3664
|
+
}
|
|
3646
3665
|
const tokenPair = session.data?._tokenPair;
|
|
3647
3666
|
if (tokenPair?.refreshToken) {
|
|
3648
|
-
await cache.kv.del(buildRefreshKey(tokenPair.refreshToken));
|
|
3667
|
+
const removeRefreshTokenResult = await cache.kv.del(buildRefreshKey(tokenPair.refreshToken));
|
|
3668
|
+
if (!removeRefreshTokenResult.success) {
|
|
3669
|
+
return buildRepositoryError(
|
|
3670
|
+
"iam_deleteSessionMappingCacheFailed",
|
|
3671
|
+
removeRefreshTokenResult.error.message,
|
|
3672
|
+
removeRefreshTokenResult.error
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3649
3675
|
}
|
|
3650
3676
|
}
|
|
3651
|
-
await cache.kv.del(
|
|
3677
|
+
const removeSessionResult = await cache.kv.del(tokenKey);
|
|
3678
|
+
if (!removeSessionResult.success) {
|
|
3679
|
+
return buildRepositoryError(
|
|
3680
|
+
"iam_deleteSessionMappingCacheFailed",
|
|
3681
|
+
removeSessionResult.error.message,
|
|
3682
|
+
removeSessionResult.error
|
|
3683
|
+
);
|
|
3684
|
+
}
|
|
3652
3685
|
return ok(void 0);
|
|
3653
3686
|
},
|
|
3654
3687
|
async removeByUserId(userId) {
|
|
3655
3688
|
const tokensResult = await cache.set_.smembers(buildUserTokensKey(userId));
|
|
3689
|
+
if (!tokensResult.success) {
|
|
3690
|
+
return buildRepositoryError(
|
|
3691
|
+
"iam_queryUserSessionCacheFailed",
|
|
3692
|
+
tokensResult.error.message,
|
|
3693
|
+
tokensResult.error
|
|
3694
|
+
);
|
|
3695
|
+
}
|
|
3656
3696
|
let removed = 0;
|
|
3657
|
-
if (tokensResult.
|
|
3697
|
+
if (tokensResult.data.length > 0) {
|
|
3658
3698
|
const results = await Promise.allSettled(
|
|
3659
3699
|
tokensResult.data.map((token) => repo.removeByAccessToken(token))
|
|
3660
3700
|
);
|
|
3661
3701
|
for (const r of results) {
|
|
3662
|
-
if (r.status === "
|
|
3663
|
-
|
|
3702
|
+
if (r.status === "rejected") {
|
|
3703
|
+
return buildRepositoryError(
|
|
3704
|
+
"iam_deleteSessionFailed",
|
|
3705
|
+
String(r.reason),
|
|
3706
|
+
r.reason
|
|
3707
|
+
);
|
|
3708
|
+
}
|
|
3709
|
+
if (!r.value.success)
|
|
3710
|
+
return r.value;
|
|
3711
|
+
removed += 1;
|
|
3664
3712
|
}
|
|
3665
3713
|
}
|
|
3666
|
-
await cache.kv.del(buildUserTokensKey(userId));
|
|
3714
|
+
const removeUserTokensKeyResult = await cache.kv.del(buildUserTokensKey(userId));
|
|
3715
|
+
if (!removeUserTokensKeyResult.success) {
|
|
3716
|
+
return buildRepositoryError(
|
|
3717
|
+
"iam_deleteUserSessionCacheFailed",
|
|
3718
|
+
removeUserTokensKeyResult.error.message,
|
|
3719
|
+
removeUserTokensKeyResult.error
|
|
3720
|
+
);
|
|
3721
|
+
}
|
|
3667
3722
|
return ok(removed);
|
|
3668
3723
|
},
|
|
3669
3724
|
async getByRefreshToken(refreshToken) {
|
|
@@ -3714,8 +3769,13 @@ function createCacheSessionRepository(sessionMaxAge, refreshTokenMaxAge) {
|
|
|
3714
3769
|
const staleTokens = [];
|
|
3715
3770
|
const writeOps = [];
|
|
3716
3771
|
for (const entry of readResults) {
|
|
3717
|
-
if (entry.status === "rejected")
|
|
3718
|
-
|
|
3772
|
+
if (entry.status === "rejected") {
|
|
3773
|
+
return buildRepositoryError(
|
|
3774
|
+
"iam_queryUserSessionCacheFailed",
|
|
3775
|
+
String(entry.reason),
|
|
3776
|
+
entry.reason
|
|
3777
|
+
);
|
|
3778
|
+
}
|
|
3719
3779
|
const { token, sessionKey, sessionResult, ttlResult } = entry.value;
|
|
3720
3780
|
if (!sessionResult.success || !sessionResult.data || !ttlResult.success || ttlResult.data <= 0) {
|
|
3721
3781
|
staleTokens.push(token);
|
|
@@ -3725,16 +3785,31 @@ function createCacheSessionRepository(sessionMaxAge, refreshTokenMaxAge) {
|
|
|
3725
3785
|
writeOps.push(cache.kv.set(sessionKey, updated, { ex: ttlResult.data }));
|
|
3726
3786
|
}
|
|
3727
3787
|
const writeResults = await Promise.allSettled(writeOps);
|
|
3728
|
-
const
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3788
|
+
for (const writeResult of writeResults) {
|
|
3789
|
+
if (writeResult.status === "rejected") {
|
|
3790
|
+
return buildRepositoryError(
|
|
3791
|
+
"iam_saveUserSessionCacheFailed",
|
|
3792
|
+
String(writeResult.reason),
|
|
3793
|
+
writeResult.reason
|
|
3794
|
+
);
|
|
3795
|
+
}
|
|
3796
|
+
if (!writeResult.value.success) {
|
|
3797
|
+
return buildRepositoryError(
|
|
3798
|
+
"iam_saveUserSessionCacheFailed",
|
|
3799
|
+
writeResult.value.error.message,
|
|
3800
|
+
writeResult.value.error
|
|
3801
|
+
);
|
|
3802
|
+
}
|
|
3735
3803
|
}
|
|
3736
3804
|
if (staleTokens.length > 0) {
|
|
3737
|
-
await cache.set_.srem(buildUserTokensKey(userId), ...staleTokens);
|
|
3805
|
+
const staleCleanupResult = await cache.set_.srem(buildUserTokensKey(userId), ...staleTokens);
|
|
3806
|
+
if (!staleCleanupResult.success) {
|
|
3807
|
+
return buildRepositoryError(
|
|
3808
|
+
"iam_deleteUserSessionCacheFailed",
|
|
3809
|
+
staleCleanupResult.error.message,
|
|
3810
|
+
staleCleanupResult.error
|
|
3811
|
+
);
|
|
3812
|
+
}
|
|
3738
3813
|
}
|
|
3739
3814
|
return ok(void 0);
|
|
3740
3815
|
}
|
|
@@ -3825,15 +3900,21 @@ function buildSessionFunctions(config) {
|
|
|
3825
3900
|
return ok(null);
|
|
3826
3901
|
}
|
|
3827
3902
|
if (/* @__PURE__ */ new Date() > session.expiresAt) {
|
|
3828
|
-
await repo.removeByAccessToken(accessToken);
|
|
3903
|
+
const removeResult = await repo.removeByAccessToken(accessToken);
|
|
3904
|
+
if (!removeResult.success) {
|
|
3905
|
+
return removeResult;
|
|
3906
|
+
}
|
|
3829
3907
|
return ok(null);
|
|
3830
3908
|
}
|
|
3831
3909
|
if (sliding) {
|
|
3832
3910
|
const now = /* @__PURE__ */ new Date();
|
|
3833
|
-
await repo.updateByAccessToken(accessToken, {
|
|
3911
|
+
const updateResult = await repo.updateByAccessToken(accessToken, {
|
|
3834
3912
|
lastActiveAt: now,
|
|
3835
3913
|
expiresAt: new Date(now.getTime() + maxAge * 1e3)
|
|
3836
3914
|
});
|
|
3915
|
+
if (!updateResult.success) {
|
|
3916
|
+
return updateResult;
|
|
3917
|
+
}
|
|
3837
3918
|
}
|
|
3838
3919
|
return ok(stripInternalSessionFields(session));
|
|
3839
3920
|
},
|
|
@@ -3877,7 +3958,10 @@ function buildSessionFunctions(config) {
|
|
|
3877
3958
|
iamM("iam_refreshTokenExpired")
|
|
3878
3959
|
);
|
|
3879
3960
|
}
|
|
3880
|
-
await repo.removeByAccessToken(oldSession.accessToken);
|
|
3961
|
+
const removeOldSessionResult = await repo.removeByAccessToken(oldSession.accessToken);
|
|
3962
|
+
if (!removeOldSessionResult.success) {
|
|
3963
|
+
return removeOldSessionResult;
|
|
3964
|
+
}
|
|
3881
3965
|
const newSessionResult = await this.create({
|
|
3882
3966
|
userId: oldSession.userId,
|
|
3883
3967
|
username: oldSession.username,
|
|
@@ -3929,12 +4013,23 @@ function hashResetToken(token) {
|
|
|
3929
4013
|
}
|
|
3930
4014
|
var RESET_TOKEN_KEY_PREFIX = "hai:iam:reset:";
|
|
3931
4015
|
var RESET_ATTEMPTS_KEY_PREFIX = "hai:iam:reset:attempts:";
|
|
4016
|
+
var RESET_USER_TOKEN_KEY_PREFIX = "hai:iam:reset:user:";
|
|
3932
4017
|
function buildResetTokenKey(hashedToken) {
|
|
3933
4018
|
return `${RESET_TOKEN_KEY_PREFIX}${hashedToken}`;
|
|
3934
4019
|
}
|
|
3935
4020
|
function buildAttemptsKey(userId) {
|
|
3936
4021
|
return `${RESET_ATTEMPTS_KEY_PREFIX}${userId}`;
|
|
3937
4022
|
}
|
|
4023
|
+
function buildUserTokenKey(userId) {
|
|
4024
|
+
return `${RESET_USER_TOKEN_KEY_PREFIX}${userId}`;
|
|
4025
|
+
}
|
|
4026
|
+
function buildResetTokenRepositoryError(messageKey, message, cause) {
|
|
4027
|
+
return err(
|
|
4028
|
+
HaiIamError.REPOSITORY_ERROR,
|
|
4029
|
+
iamM(messageKey, { params: { message } }),
|
|
4030
|
+
cause
|
|
4031
|
+
);
|
|
4032
|
+
}
|
|
3938
4033
|
var resetTokenRepoInstance = null;
|
|
3939
4034
|
function resetResetTokenRepoSingleton() {
|
|
3940
4035
|
resetTokenRepoInstance = null;
|
|
@@ -3942,6 +4037,22 @@ function resetResetTokenRepoSingleton() {
|
|
|
3942
4037
|
function createCacheResetTokenRepository() {
|
|
3943
4038
|
if (resetTokenRepoInstance)
|
|
3944
4039
|
return resetTokenRepoInstance;
|
|
4040
|
+
async function clearTokenState(hashedToken, userId) {
|
|
4041
|
+
const cleanupResults = await Promise.all([
|
|
4042
|
+
cache.kv.del(buildResetTokenKey(hashedToken)),
|
|
4043
|
+
cache.kv.del(buildAttemptsKey(userId)),
|
|
4044
|
+
cache.kv.del(buildUserTokenKey(userId))
|
|
4045
|
+
]);
|
|
4046
|
+
const failedCleanup = cleanupResults.find((result) => !result.success);
|
|
4047
|
+
if (failedCleanup && !failedCleanup.success) {
|
|
4048
|
+
return buildResetTokenRepositoryError(
|
|
4049
|
+
"iam_saveResetTokenFailed",
|
|
4050
|
+
failedCleanup.error.message,
|
|
4051
|
+
failedCleanup.error
|
|
4052
|
+
);
|
|
4053
|
+
}
|
|
4054
|
+
return ok(void 0);
|
|
4055
|
+
}
|
|
3945
4056
|
const repo = {
|
|
3946
4057
|
async saveToken(token, userId, expiresAt) {
|
|
3947
4058
|
const hashResult = hashResetToken(token);
|
|
@@ -3950,6 +4061,25 @@ function createCacheResetTokenRepository() {
|
|
|
3950
4061
|
}
|
|
3951
4062
|
const hashedToken = hashResult.data;
|
|
3952
4063
|
const ttlSeconds = Math.max(1, Math.ceil((expiresAt.getTime() - Date.now()) / 1e3));
|
|
4064
|
+
const userTokenKey = buildUserTokenKey(userId);
|
|
4065
|
+
const existingTokenResult = await cache.kv.get(userTokenKey);
|
|
4066
|
+
if (!existingTokenResult.success) {
|
|
4067
|
+
return buildResetTokenRepositoryError(
|
|
4068
|
+
"iam_queryResetTokenFailed",
|
|
4069
|
+
existingTokenResult.error.message,
|
|
4070
|
+
existingTokenResult.error
|
|
4071
|
+
);
|
|
4072
|
+
}
|
|
4073
|
+
if (existingTokenResult.data && existingTokenResult.data !== hashedToken) {
|
|
4074
|
+
const removeExistingTokenResult = await cache.kv.del(buildResetTokenKey(existingTokenResult.data));
|
|
4075
|
+
if (!removeExistingTokenResult.success) {
|
|
4076
|
+
return buildResetTokenRepositoryError(
|
|
4077
|
+
"iam_saveResetTokenFailed",
|
|
4078
|
+
removeExistingTokenResult.error.message,
|
|
4079
|
+
removeExistingTokenResult.error
|
|
4080
|
+
);
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
3953
4083
|
const setResult = await cache.kv.set(buildResetTokenKey(hashedToken), userId, { ex: ttlSeconds });
|
|
3954
4084
|
if (!setResult.success) {
|
|
3955
4085
|
return err(
|
|
@@ -3958,11 +4088,24 @@ function createCacheResetTokenRepository() {
|
|
|
3958
4088
|
setResult.error
|
|
3959
4089
|
);
|
|
3960
4090
|
}
|
|
4091
|
+
const saveUserTokenResult = await cache.kv.set(userTokenKey, hashedToken, { ex: ttlSeconds });
|
|
4092
|
+
if (!saveUserTokenResult.success) {
|
|
4093
|
+
await cache.kv.del(buildResetTokenKey(hashedToken));
|
|
4094
|
+
return buildResetTokenRepositoryError(
|
|
4095
|
+
"iam_saveResetTokenFailed",
|
|
4096
|
+
saveUserTokenResult.error.message,
|
|
4097
|
+
saveUserTokenResult.error
|
|
4098
|
+
);
|
|
4099
|
+
}
|
|
3961
4100
|
const attemptsResult = await cache.kv.set(buildAttemptsKey(userId), 0, { ex: ttlSeconds });
|
|
3962
4101
|
if (!attemptsResult.success) {
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
4102
|
+
await Promise.all([
|
|
4103
|
+
cache.kv.del(buildResetTokenKey(hashedToken)),
|
|
4104
|
+
cache.kv.del(userTokenKey)
|
|
4105
|
+
]);
|
|
4106
|
+
return buildResetTokenRepositoryError(
|
|
4107
|
+
"iam_saveResetTokenFailed",
|
|
4108
|
+
attemptsResult.error.message,
|
|
3966
4109
|
attemptsResult.error
|
|
3967
4110
|
);
|
|
3968
4111
|
}
|
|
@@ -3992,10 +4135,19 @@ function createCacheResetTokenRepository() {
|
|
|
3992
4135
|
const userId = result.data;
|
|
3993
4136
|
const attemptsKey = buildAttemptsKey(userId);
|
|
3994
4137
|
const incrResult = await cache.kv.incr(attemptsKey);
|
|
3995
|
-
|
|
4138
|
+
if (!incrResult.success) {
|
|
4139
|
+
return buildResetTokenRepositoryError(
|
|
4140
|
+
"iam_saveResetTokenFailed",
|
|
4141
|
+
incrResult.error.message,
|
|
4142
|
+
incrResult.error
|
|
4143
|
+
);
|
|
4144
|
+
}
|
|
4145
|
+
const nextAttempts = incrResult.data;
|
|
3996
4146
|
if (nextAttempts > maxAttempts) {
|
|
3997
|
-
await
|
|
3998
|
-
|
|
4147
|
+
const clearResult = await clearTokenState(hashedToken, userId);
|
|
4148
|
+
if (!clearResult.success) {
|
|
4149
|
+
return clearResult;
|
|
4150
|
+
}
|
|
3999
4151
|
return err(
|
|
4000
4152
|
HaiIamError.RESET_TOKEN_MAX_ATTEMPTS,
|
|
4001
4153
|
iamM("iam_resetTokenMaxAttempts")
|
|
@@ -4011,11 +4163,17 @@ function createCacheResetTokenRepository() {
|
|
|
4011
4163
|
const hashedToken = hashResult.data;
|
|
4012
4164
|
const tokenKey = buildResetTokenKey(hashedToken);
|
|
4013
4165
|
const result = await cache.kv.get(tokenKey);
|
|
4014
|
-
if (result.success
|
|
4015
|
-
|
|
4166
|
+
if (!result.success) {
|
|
4167
|
+
return buildResetTokenRepositoryError(
|
|
4168
|
+
"iam_queryResetTokenFailed",
|
|
4169
|
+
result.error.message,
|
|
4170
|
+
result.error
|
|
4171
|
+
);
|
|
4016
4172
|
}
|
|
4017
|
-
|
|
4018
|
-
|
|
4173
|
+
if (!result.data) {
|
|
4174
|
+
return ok(void 0);
|
|
4175
|
+
}
|
|
4176
|
+
return clearTokenState(hashedToken, result.data);
|
|
4019
4177
|
}
|
|
4020
4178
|
};
|
|
4021
4179
|
resetTokenRepoInstance = repo;
|
|
@@ -4136,18 +4294,6 @@ function buildRegistrationOps(ctx) {
|
|
|
4136
4294
|
}
|
|
4137
4295
|
return ok(void 0);
|
|
4138
4296
|
}
|
|
4139
|
-
function buildAgreementDisplay() {
|
|
4140
|
-
if (!agreementConfig.showOnRegister)
|
|
4141
|
-
return void 0;
|
|
4142
|
-
if (!agreementConfig.userAgreementUrl && !agreementConfig.privacyPolicyUrl)
|
|
4143
|
-
return void 0;
|
|
4144
|
-
return {
|
|
4145
|
-
userAgreementUrl: agreementConfig.userAgreementUrl,
|
|
4146
|
-
privacyPolicyUrl: agreementConfig.privacyPolicyUrl,
|
|
4147
|
-
showOnRegister: agreementConfig.showOnRegister,
|
|
4148
|
-
showOnLogin: agreementConfig.showOnLogin
|
|
4149
|
-
};
|
|
4150
|
-
}
|
|
4151
4297
|
async function assignDefaultRole(userId) {
|
|
4152
4298
|
if (!config.rbac?.defaultRole)
|
|
4153
4299
|
return;
|
|
@@ -4202,7 +4348,7 @@ function buildRegistrationOps(ctx) {
|
|
|
4202
4348
|
logger9.info("User registered", { userId: createdUser.id, username: options.username });
|
|
4203
4349
|
return ok({
|
|
4204
4350
|
user: toUser(createdUser),
|
|
4205
|
-
agreements: buildAgreementDisplay()
|
|
4351
|
+
agreements: buildAgreementDisplay(agreementConfig, agreementConfig.showOnRegister)
|
|
4206
4352
|
});
|
|
4207
4353
|
},
|
|
4208
4354
|
validatePassword(password) {
|
|
@@ -4789,7 +4935,7 @@ var iam = {
|
|
|
4789
4935
|
return currentApiKey ?? notInitializedApiKey;
|
|
4790
4936
|
},
|
|
4791
4937
|
get config() {
|
|
4792
|
-
return currentConfig;
|
|
4938
|
+
return currentConfig ? core.sanitize.sanitizeSensitiveFields(currentConfig) : null;
|
|
4793
4939
|
},
|
|
4794
4940
|
get isInitialized() {
|
|
4795
4941
|
return currentConfig !== null;
|