mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
🐛 fix: eSIM 交换流程补齐/归一化 MFA ref 并增强校验
- 在 eSIM 交换前对 mfaRef 进行 trim 归一化,按需同时设置 X-MFA-Ref 与 X-MFA-Challenge-Ref,并将 mfaRef 作为 GraphQL 顶层字段传入 - 完整短信激活流程中统一从 MFA 校验结果 ref 或 emailCodeRef 获取并校验 swapMfaRef,缺失时抛出缺少 ref 的本地化错误 - MFA 校验增加对 signature 缺失的保护,成功返回时同时携带 ref 供后续交换步骤使用 - Netlify GraphQL 代理函数解析 X-MFA-Ref / X-MFA-Challenge-Ref 与请求体中的 mfaRef,进行 trim 后优先取体内 ref 并回填到 graphqlBody.mfaRef,确保 schema 需要的顶层字段始终可用
This commit is contained in:
@@ -29,6 +29,10 @@ exports.handler = withAuth(async (event, context, { auth, body }) => {
|
||||
Object.entries(event.headers || {}).map(([k, v]) => [String(k).toLowerCase(), v])
|
||||
);
|
||||
const authHeader = lowerCaseHeaders['authorization'] || '';
|
||||
const headerMfaRefRaw = lowerCaseHeaders['x-mfa-ref'] || lowerCaseHeaders['x-mfa-challenge-ref'] || '';
|
||||
const headerMfaRef = typeof headerMfaRefRaw === 'string' ? headerMfaRefRaw.trim() : '';
|
||||
const bodyMfaRef = typeof mfaRef === 'string' ? mfaRef.trim() : '';
|
||||
const resolvedMfaRef = bodyMfaRef || headerMfaRef;
|
||||
let accessToken = body.accessToken;
|
||||
if (!accessToken && authHeader.startsWith('Bearer ')) {
|
||||
accessToken = authHeader.slice(7);
|
||||
@@ -94,8 +98,8 @@ exports.handler = withAuth(async (event, context, { auth, body }) => {
|
||||
};
|
||||
|
||||
// swapSim 需要 mfaRef 作为顶层字段(Giffgaff schema 要求)
|
||||
if (mfaRef) {
|
||||
graphqlBody.mfaRef = mfaRef;
|
||||
if (resolvedMfaRef) {
|
||||
graphqlBody.mfaRef = resolvedMfaRef;
|
||||
}
|
||||
|
||||
// 供失败时刷新令牌使用的 verify-cookie 地址
|
||||
|
||||
@@ -138,15 +138,22 @@ export class ESimService {
|
||||
async swapSim(activationCode, mfaSignature, mfaRef) {
|
||||
try {
|
||||
const state = stateManager.getState();
|
||||
const normalizedMfaRef = typeof mfaRef === 'string' ? mfaRef.trim() : '';
|
||||
const requestHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${state.accessToken}`,
|
||||
'X-MFA-Signature': mfaSignature,
|
||||
'X-CF-Turnstile': window.__cfTurnstileToken || ''
|
||||
};
|
||||
|
||||
if (normalizedMfaRef) {
|
||||
requestHeaders['X-MFA-Ref'] = normalizedMfaRef;
|
||||
requestHeaders['X-MFA-Challenge-Ref'] = normalizedMfaRef;
|
||||
}
|
||||
|
||||
const response = await fetch(this.apiEndpoints.graphql, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${state.accessToken}`,
|
||||
'X-MFA-Signature': mfaSignature,
|
||||
'X-CF-Turnstile': window.__cfTurnstileToken || ''
|
||||
},
|
||||
headers: requestHeaders,
|
||||
body: JSON.stringify({
|
||||
accessToken: state.accessToken,
|
||||
mfaSignature: mfaSignature,
|
||||
@@ -157,7 +164,7 @@ export class ESimService {
|
||||
mfaSignature
|
||||
},
|
||||
query: graphqlQueries.swapSim,
|
||||
mfaRef
|
||||
mfaRef: normalizedMfaRef || undefined
|
||||
})
|
||||
});
|
||||
|
||||
@@ -312,10 +319,12 @@ export class ESimService {
|
||||
*/
|
||||
async smsActivateFlow(smsCode) {
|
||||
try {
|
||||
const state = stateManager.getState();
|
||||
|
||||
// 1. 验证短信验证码
|
||||
const mfaResult = await this.validateMFACodeForSwap(smsCode);
|
||||
const swapMfaRef = (mfaResult.ref || stateManager.get('emailCodeRef') || '').trim();
|
||||
if (!swapMfaRef) {
|
||||
throw new Error(t('giffgaff.mfa.errors.missingRef'));
|
||||
}
|
||||
|
||||
// 2. 预订eSIM
|
||||
const reserveResult = await this.reserveESim();
|
||||
@@ -324,7 +333,7 @@ export class ESimService {
|
||||
const swapResult = await this.swapSim(
|
||||
reserveResult.data.esim.activationCode,
|
||||
mfaResult.signature,
|
||||
state.emailCodeRef
|
||||
swapMfaRef
|
||||
);
|
||||
|
||||
// 4. 获取LPA(轮询)
|
||||
@@ -370,6 +379,11 @@ export class ESimService {
|
||||
*/
|
||||
async validateMFACodeForSwap(code) {
|
||||
const state = stateManager.getState();
|
||||
const ref = (state.emailCodeRef || '').trim();
|
||||
|
||||
if (!ref) {
|
||||
throw new Error(t('giffgaff.mfa.errors.missingRef'));
|
||||
}
|
||||
|
||||
const response = await fetch(this.apiEndpoints.mfaValidation, {
|
||||
method: 'POST',
|
||||
@@ -381,7 +395,7 @@ export class ESimService {
|
||||
body: JSON.stringify({
|
||||
accessToken: state.accessToken,
|
||||
cookie: stateManager.getCookie() || undefined,
|
||||
ref: state.emailCodeRef,
|
||||
ref,
|
||||
code,
|
||||
turnstileToken: window.__cfTurnstileToken || ''
|
||||
})
|
||||
@@ -397,9 +411,12 @@ export class ESimService {
|
||||
|
||||
const data = await response.json();
|
||||
const signature = data.signature || '';
|
||||
if (!signature) {
|
||||
throw new Error(t('giffgaff.mfa.errors.missingSignature'));
|
||||
}
|
||||
stateManager.set('emailSignature', signature);
|
||||
|
||||
return { success: true, signature };
|
||||
return { success: true, signature, ref };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user