@feelflow/ffid-sdk 5.19.0 → 5.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agency/index.cjs +4 -2
- package/dist/agency/index.js +4 -2
- package/dist/announcements/index.cjs +2 -1
- package/dist/announcements/index.js +2 -1
- package/dist/{chunk-TW2FXASO.cjs → chunk-RDQ4R3XC.cjs} +96 -49
- package/dist/{chunk-D3PZ6SZB.js → chunk-U57ZDFEN.js} +96 -49
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-BuDM5tmq.d.cts → ffid-client-BQPhm-XL.d.cts} +54 -8
- package/dist/{ffid-client-D0x8TBS5.d.ts → ffid-client-Bx8y4SwC.d.ts} +54 -8
- package/dist/{index-Bkul-fRw.d.cts → index--wRiPlpi.d.cts} +54 -8
- package/dist/{index-Bkul-fRw.d.ts → index--wRiPlpi.d.ts} +54 -8
- package/dist/index.cjs +42 -42
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/legal/index.cjs +2 -1
- package/dist/legal/index.js +2 -1
- package/dist/server/index.cjs +94 -48
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +94 -48
- package/dist/server/test/index.d.cts +1 -1
- package/dist/server/test/index.d.ts +1 -1
- package/dist/webhooks/index.cjs +2 -2
- package/dist/webhooks/index.js +2 -2
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -260,10 +260,12 @@ var OAUTH_INTROSPECT_ENDPOINT = "/api/v1/oauth/introspect";
|
|
|
260
260
|
var CACHE_KEY_PREFIX = "ffid:introspect:";
|
|
261
261
|
var HEX_BASE = 16;
|
|
262
262
|
var HEX_BYTE_WIDTH = 2;
|
|
263
|
-
var TOKEN_LOG_PREFIX_LENGTH = 8;
|
|
264
263
|
function createVerifyAccessToken(deps) {
|
|
265
264
|
const { authMode, baseUrl, serviceCode, serviceApiKey, verifyStrategy, logger, createError, errorCodes, cache, timeout } = deps;
|
|
266
265
|
let jwtVerify2 = null;
|
|
266
|
+
let cacheReadFailureEscalated = false;
|
|
267
|
+
let cacheWriteFailureEscalated = false;
|
|
268
|
+
let missingSubtleCryptoLogged = false;
|
|
267
269
|
function getJwtVerifier() {
|
|
268
270
|
if (!jwtVerify2) {
|
|
269
271
|
jwtVerify2 = createJwtVerifier({
|
|
@@ -323,8 +325,9 @@ function createVerifyAccessToken(deps) {
|
|
|
323
325
|
}
|
|
324
326
|
const url = `${baseUrl}${OAUTH_INTROSPECT_ENDPOINT}`;
|
|
325
327
|
logger.debug("Verifying access token:", url);
|
|
326
|
-
const cacheKey = cache ? await buildCacheKey(accessToken, cacheKeySuffix) :
|
|
327
|
-
|
|
328
|
+
const cacheKey = cache ? await buildCacheKey(accessToken, cacheKeySuffix) : null;
|
|
329
|
+
let verificationCacheDegraded = cache !== void 0 && cacheKey === null;
|
|
330
|
+
if (cache && cacheKey !== null) {
|
|
328
331
|
try {
|
|
329
332
|
const cached = await cache.adapter.get(cacheKey);
|
|
330
333
|
if (cached && typeof cached === "object" && "sub" in cached) {
|
|
@@ -332,7 +335,16 @@ function createVerifyAccessToken(deps) {
|
|
|
332
335
|
return { data: cached };
|
|
333
336
|
}
|
|
334
337
|
} catch (cacheError) {
|
|
335
|
-
|
|
338
|
+
verificationCacheDegraded = true;
|
|
339
|
+
if (!cacheReadFailureEscalated) {
|
|
340
|
+
cacheReadFailureEscalated = true;
|
|
341
|
+
logger.error(
|
|
342
|
+
"Cache read failed \u2014 falling back to API call. Redis \u7B49\u306E cache adapter \u969C\u5BB3\u6642\u306F\u5168 verification \u304C introspect \u306B degrade \u3057\u307E\u3059\uFF08\u3053\u306E error \u306F instance \u3054\u3068\u306B\u521D\u56DE\u306E\u307F\u3001\u4EE5\u964D\u306F warn\uFF09:",
|
|
343
|
+
cacheError
|
|
344
|
+
);
|
|
345
|
+
} else {
|
|
346
|
+
logger.warn("Cache read failed, falling back to API call:", cacheError);
|
|
347
|
+
}
|
|
336
348
|
}
|
|
337
349
|
}
|
|
338
350
|
const fetchOptions = {
|
|
@@ -427,31 +439,40 @@ function createVerifyAccessToken(deps) {
|
|
|
427
439
|
}
|
|
428
440
|
} : base;
|
|
429
441
|
const userinfo = normalizeUserinfo(raw);
|
|
430
|
-
if (cache) {
|
|
442
|
+
if (cache && cacheKey !== null) {
|
|
431
443
|
try {
|
|
432
444
|
await cache.adapter.set(cacheKey, userinfo, cache.ttl);
|
|
433
445
|
} catch (cacheError) {
|
|
434
|
-
|
|
446
|
+
verificationCacheDegraded = true;
|
|
447
|
+
if (!cacheWriteFailureEscalated) {
|
|
448
|
+
cacheWriteFailureEscalated = true;
|
|
449
|
+
logger.error(
|
|
450
|
+
"Cache write failed \u2014 result still returned. cache adapter \u969C\u5BB3\u6642\u306F introspect \u7D50\u679C\u304C\u30AD\u30E3\u30C3\u30B7\u30E5\u3055\u308C\u305A\u5168 verification \u304C API \u547C\u3073\u51FA\u3057\u306B degrade \u3057\u307E\u3059\uFF08\u3053\u306E error \u306F instance \u3054\u3068\u306B\u521D\u56DE\u306E\u307F\u3001\u4EE5\u964D\u306F warn\uFF09:",
|
|
451
|
+
cacheError
|
|
452
|
+
);
|
|
453
|
+
} else {
|
|
454
|
+
logger.warn("Cache write failed (result still returned):", cacheError);
|
|
455
|
+
}
|
|
435
456
|
}
|
|
436
457
|
}
|
|
437
|
-
return { data: userinfo };
|
|
458
|
+
return verificationCacheDegraded ? { data: userinfo, meta: { verificationCacheDegraded: true } } : { data: userinfo };
|
|
438
459
|
}
|
|
439
460
|
async function buildCacheKey(token, suffix) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
461
|
+
if (typeof globalThis.crypto?.subtle?.digest !== "function") {
|
|
462
|
+
if (!missingSubtleCryptoLogged) {
|
|
463
|
+
missingSubtleCryptoLogged = true;
|
|
464
|
+
logger.error(
|
|
465
|
+
"crypto.subtle \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 introspect \u7D50\u679C\u306E\u30AD\u30E3\u30C3\u30B7\u30E5\u3092\u7121\u52B9\u5316\u3057\u307E\u3057\u305F\uFF08\u30CF\u30C3\u30B7\u30E5\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u30C8\u30FC\u30AF\u30F3\u3092 cache key \u306B\u4F7F\u308F\u306A\u3044\u305F\u3081\u306E\u63AA\u7F6E #4119\uFF09\u3002\u5168 verification \u304C API \u547C\u3073\u51FA\u3057\u306B\u306A\u308A\u307E\u3059"
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
const encoder = new TextEncoder();
|
|
471
|
+
const data = encoder.encode(token);
|
|
472
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
473
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
474
|
+
const hashHex = hashArray.map((b) => b.toString(HEX_BASE).padStart(HEX_BYTE_WIDTH, "0")).join("");
|
|
475
|
+
const key = CACHE_KEY_PREFIX + hashHex;
|
|
455
476
|
return suffix ? `${key}:${suffix}` : key;
|
|
456
477
|
}
|
|
457
478
|
return verifyAccessToken;
|
|
@@ -1200,7 +1221,7 @@ function createNonContractMethods(deps) {
|
|
|
1200
1221
|
}
|
|
1201
1222
|
|
|
1202
1223
|
// src/client/version-check.ts
|
|
1203
|
-
var SDK_VERSION = "5.
|
|
1224
|
+
var SDK_VERSION = "5.21.0";
|
|
1204
1225
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1205
1226
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1206
1227
|
function sdkHeaders() {
|
|
@@ -1442,33 +1463,48 @@ function createOAuthTokenMethods(deps) {
|
|
|
1442
1463
|
async function signOutToken() {
|
|
1443
1464
|
const tokens = tokenStore.getTokens();
|
|
1444
1465
|
tokenStore.clearTokens();
|
|
1466
|
+
const allRevoked = {
|
|
1467
|
+
revoked: true,
|
|
1468
|
+
accessTokenRevoked: true,
|
|
1469
|
+
refreshTokenRevoked: true
|
|
1470
|
+
};
|
|
1445
1471
|
if (!tokens) {
|
|
1446
1472
|
logger.debug("No tokens to revoke");
|
|
1447
|
-
return { data:
|
|
1473
|
+
return { data: allRevoked };
|
|
1448
1474
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
);
|
|
1475
|
+
async function revokeOAuthToken(token, tokenTypeHint) {
|
|
1476
|
+
const url = `${baseUrl}${OAUTH_REVOKE_ENDPOINT}`;
|
|
1477
|
+
try {
|
|
1478
|
+
const response = await fetch(url, {
|
|
1479
|
+
method: "POST",
|
|
1480
|
+
credentials: "omit",
|
|
1481
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", ...sdkHeaders() },
|
|
1482
|
+
body: new URLSearchParams({
|
|
1483
|
+
token,
|
|
1484
|
+
client_id: clientId,
|
|
1485
|
+
token_type_hint: tokenTypeHint
|
|
1486
|
+
}).toString()
|
|
1487
|
+
});
|
|
1488
|
+
return response.ok;
|
|
1489
|
+
} catch {
|
|
1490
|
+
return false;
|
|
1466
1491
|
}
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1492
|
+
}
|
|
1493
|
+
logger.debug("Revoking tokens:", `${baseUrl}${OAUTH_REVOKE_ENDPOINT}`);
|
|
1494
|
+
const accessTokenRevoked = await revokeOAuthToken(tokens.accessToken, "access_token");
|
|
1495
|
+
if (!accessTokenRevoked) {
|
|
1496
|
+
logger.warn("\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306E\u7121\u52B9\u5316\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u30B5\u30FC\u30D0\u30FC\u3067\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
1497
|
+
}
|
|
1498
|
+
const refreshTokenRevoked = tokens.refreshToken ? await revokeOAuthToken(tokens.refreshToken, "refresh_token") : true;
|
|
1499
|
+
if (tokens.refreshToken && !refreshTokenRevoked) {
|
|
1500
|
+
logger.warn("\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5\u30C8\u30FC\u30AF\u30F3\u306E\u7121\u52B9\u5316\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u30B5\u30FC\u30D0\u30FC\u3067\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
1501
|
+
}
|
|
1502
|
+
const revoked = accessTokenRevoked && refreshTokenRevoked;
|
|
1503
|
+
if (!revoked) {
|
|
1504
|
+
logger.warn("\u30C8\u30FC\u30AF\u30F3\u7121\u52B9\u5316\u304C\u4E00\u90E8\u307E\u305F\u306F\u5168\u90E8\u5931\u6557\u3057\u307E\u3057\u305F\uFF08\u30ED\u30FC\u30AB\u30EB\u30C8\u30FC\u30AF\u30F3\u306F\u30AF\u30EA\u30A2\u6E08\u307F\uFF09");
|
|
1469
1505
|
}
|
|
1470
1506
|
logger.debug("Token sign-out completed");
|
|
1471
|
-
return { data:
|
|
1507
|
+
return { data: { revoked, accessTokenRevoked, refreshTokenRevoked } };
|
|
1472
1508
|
}
|
|
1473
1509
|
return { exchangeCodeForTokens, refreshAccessToken, signOutToken };
|
|
1474
1510
|
}
|
|
@@ -1632,7 +1668,7 @@ function createSessionMethods(deps) {
|
|
|
1632
1668
|
}
|
|
1633
1669
|
if (response.status === NO_CONTENT_STATUS) {
|
|
1634
1670
|
logger.debug("Response: 204 No Content");
|
|
1635
|
-
return { data:
|
|
1671
|
+
return { data: { revoked: true } };
|
|
1636
1672
|
}
|
|
1637
1673
|
if (!response.ok) {
|
|
1638
1674
|
try {
|
|
@@ -1659,7 +1695,7 @@ function createSessionMethods(deps) {
|
|
|
1659
1695
|
}
|
|
1660
1696
|
}
|
|
1661
1697
|
logger.debug("Response:", response.status);
|
|
1662
|
-
return { data:
|
|
1698
|
+
return { data: { revoked: true } };
|
|
1663
1699
|
}
|
|
1664
1700
|
return { getSession, signOutCookie };
|
|
1665
1701
|
}
|
|
@@ -1782,6 +1818,9 @@ var REDIRECT_LOOP_WINDOW_MS = 6e4;
|
|
|
1782
1818
|
var REDIRECT_LOOP_THRESHOLD = 3;
|
|
1783
1819
|
var storageReadFailureLogged = false;
|
|
1784
1820
|
var storageWriteFailureLogged = false;
|
|
1821
|
+
function isLoopDetectionDegraded() {
|
|
1822
|
+
return storageReadFailureLogged || storageWriteFailureLogged;
|
|
1823
|
+
}
|
|
1785
1824
|
function logStorageReadFailure(logger, err) {
|
|
1786
1825
|
if (storageReadFailureLogged) return;
|
|
1787
1826
|
storageReadFailureLogged = true;
|
|
@@ -1926,9 +1965,16 @@ function createRedirectMethods(deps) {
|
|
|
1926
1965
|
}
|
|
1927
1966
|
const state = generateRandomState();
|
|
1928
1967
|
if (!storeState(state, logger)) {
|
|
1968
|
+
cleanupVerifierStorage(logger);
|
|
1969
|
+
cleanupStateStorage(logger);
|
|
1929
1970
|
logger.error(
|
|
1930
|
-
"redirectToAuthorize: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\uFF08storage \u5229\u7528\u4E0D\u53EF\uFF09\u3002\
|
|
1971
|
+
"redirectToAuthorize: OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\uFF08storage \u5229\u7528\u4E0D\u53EF\uFF09\u3002\u8A8D\u53EF\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
|
|
1931
1972
|
);
|
|
1973
|
+
return {
|
|
1974
|
+
success: false,
|
|
1975
|
+
code: "state_persistence_failed",
|
|
1976
|
+
error: "OAuth state \u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\uFF08storage \u5229\u7528\u4E0D\u53EF\uFF09\u3002\u8A8D\u53EF\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F"
|
|
1977
|
+
};
|
|
1932
1978
|
}
|
|
1933
1979
|
const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
|
|
1934
1980
|
const params = new URLSearchParams({
|
|
@@ -1963,7 +2009,7 @@ function createRedirectMethods(deps) {
|
|
|
1963
2009
|
rollbackLastRedirectAttempt(authorizeKey, logger);
|
|
1964
2010
|
throw err;
|
|
1965
2011
|
}
|
|
1966
|
-
return { success: true };
|
|
2012
|
+
return isLoopDetectionDegraded() ? { success: true, loopDetectionDisabled: true } : { success: true };
|
|
1967
2013
|
}
|
|
1968
2014
|
async function redirectToLogin(options) {
|
|
1969
2015
|
if (typeof window === "undefined") {
|
package/dist/webhooks/index.cjs
CHANGED
|
@@ -89,7 +89,6 @@ function verifyWebhookSignature(rawBody, signatureHeader, secret, toleranceSecon
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// src/webhooks/handler.ts
|
|
92
|
-
var SDK_LOG_PREFIX = "[FFID Webhook SDK]";
|
|
93
92
|
var HTTP_OK = 200;
|
|
94
93
|
var HTTP_BAD_REQUEST = 400;
|
|
95
94
|
var HTTP_INTERNAL_SERVER_ERROR = 500;
|
|
@@ -100,7 +99,8 @@ var noopLogger = {
|
|
|
100
99
|
},
|
|
101
100
|
warn: () => {
|
|
102
101
|
},
|
|
103
|
-
error: (
|
|
102
|
+
error: () => {
|
|
103
|
+
}
|
|
104
104
|
};
|
|
105
105
|
function createFFIDWebhookHandler(config) {
|
|
106
106
|
if (!config.secret) {
|
package/dist/webhooks/index.js
CHANGED
|
@@ -87,7 +87,6 @@ function verifyWebhookSignature(rawBody, signatureHeader, secret, toleranceSecon
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// src/webhooks/handler.ts
|
|
90
|
-
var SDK_LOG_PREFIX = "[FFID Webhook SDK]";
|
|
91
90
|
var HTTP_OK = 200;
|
|
92
91
|
var HTTP_BAD_REQUEST = 400;
|
|
93
92
|
var HTTP_INTERNAL_SERVER_ERROR = 500;
|
|
@@ -98,7 +97,8 @@ var noopLogger = {
|
|
|
98
97
|
},
|
|
99
98
|
warn: () => {
|
|
100
99
|
},
|
|
101
|
-
error: (
|
|
100
|
+
error: () => {
|
|
101
|
+
}
|
|
102
102
|
};
|
|
103
103
|
function createFFIDWebhookHandler(config) {
|
|
104
104
|
if (!config.secret) {
|