mirror of
https://github.com/halfwaystudent/douyin-sparkflow.git
synced 2026-09-06 07:57:09 +08:00
Import sanitized project structure and GitHub docs
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const {
|
||||
combineDistinctTextParts,
|
||||
extractVerificationCode,
|
||||
generateReadableLocalPart,
|
||||
parseAdminTimestamp,
|
||||
parseCloudflareMailboxCredential,
|
||||
pickRandomSuffix,
|
||||
selectVerificationMessage,
|
||||
} = require('../shared/cloudflare-temp-email.js');
|
||||
|
||||
function createJwt(payload) {
|
||||
const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
|
||||
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
||||
return `${header}.${body}.signature`;
|
||||
}
|
||||
|
||||
test('parseCloudflareMailboxCredential decodes email and address id from JWT token', () => {
|
||||
const token = createJwt({
|
||||
address: 'newmask@co.example.test',
|
||||
address_id: 42,
|
||||
});
|
||||
|
||||
assert.deepEqual(parseCloudflareMailboxCredential(token), {
|
||||
addressId: 42,
|
||||
domain: 'co.example.test',
|
||||
email: 'newmask@co.example.test',
|
||||
localPart: 'newmask',
|
||||
provenance: 'created',
|
||||
});
|
||||
});
|
||||
|
||||
test('parseAdminTimestamp parses admin timestamps into epoch milliseconds', () => {
|
||||
const value = parseAdminTimestamp('2026/4/7 10:33:07');
|
||||
assert.equal(Number.isFinite(value), true);
|
||||
assert.equal(new Date(value).getFullYear(), 2026);
|
||||
});
|
||||
|
||||
test('extractVerificationCode reads six-digit codes from mixed-language subjects', () => {
|
||||
assert.equal(extractVerificationCode('Your ChatGPT code is 377680'), '377680');
|
||||
assert.equal(extractVerificationCode('你的 ChatGPT 代码为 479637,请勿泄露。'), '479637');
|
||||
});
|
||||
|
||||
test('combineDistinctTextParts collapses duplicated text fragments from DOM sources', () => {
|
||||
const value = combineDistinctTextParts([
|
||||
'账号',
|
||||
'账号',
|
||||
' 账号 ',
|
||||
'',
|
||||
null,
|
||||
]);
|
||||
|
||||
assert.equal(value, '账号');
|
||||
});
|
||||
|
||||
test('combineDistinctTextParts keeps distinct fragments in order', () => {
|
||||
const value = combineDistinctTextParts([
|
||||
'邮箱地址凭证',
|
||||
'token-value',
|
||||
'token-value',
|
||||
'关闭',
|
||||
]);
|
||||
|
||||
assert.equal(value, '邮箱地址凭证 token-value 关闭');
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart creates three lowercase hyphenated words', () => {
|
||||
const value = generateReadableLocalPart(() => 0);
|
||||
|
||||
assert.match(value, /^[a-z]+-[a-z]+-[a-z]+$/);
|
||||
assert.equal(value.split('-').length, 3);
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart is deterministic for a fixed random sequence', () => {
|
||||
const sequence = [0.02, 0.31, 0.58];
|
||||
let index = 0;
|
||||
const value = generateReadableLocalPart(() => sequence[index++]);
|
||||
|
||||
assert.equal(value, 'anew-dotted-latch');
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart retries until the generated local part fits the max length', () => {
|
||||
const sequence = [
|
||||
0.98, 0.98, 0.98,
|
||||
0.02, 0.31, 0.58,
|
||||
];
|
||||
let index = 0;
|
||||
const value = generateReadableLocalPart(() => sequence[index++], 20);
|
||||
|
||||
assert.equal(value.length <= 20, true);
|
||||
assert.equal(value, 'anew-dotted-latch');
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart can use newly added higher-range words', () => {
|
||||
const sequence = [0.9, 0.9, 0.9];
|
||||
let index = 0;
|
||||
const value = generateReadableLocalPart(() => sequence[index++]);
|
||||
|
||||
assert.equal(value, 'vantage-velvet-zephyr');
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart can use extended top-range words', () => {
|
||||
const sequence = [0.97, 0.97, 0.97];
|
||||
let index = 0;
|
||||
const value = generateReadableLocalPart(() => sequence[index++]);
|
||||
|
||||
assert.equal(value, 'whimsy-marbled-solstice');
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart can use extended mid-range words', () => {
|
||||
const sequence = [0.962, 0.962, 0.962];
|
||||
let index = 0;
|
||||
const value = generateReadableLocalPart(() => sequence[index++]);
|
||||
|
||||
assert.equal(value, 'ivory-rusted-starling');
|
||||
});
|
||||
|
||||
test('generateReadableLocalPart can use extended apex-range words', () => {
|
||||
const sequence = [0.993, 0.993, 0.993];
|
||||
let index = 0;
|
||||
const value = generateReadableLocalPart(() => sequence[index++]);
|
||||
|
||||
assert.equal(value, 'atlas-bronze-cosmos');
|
||||
});
|
||||
|
||||
test('pickRandomSuffix selects a deterministic suffix from the available options', () => {
|
||||
const value = pickRandomSuffix([
|
||||
'co.example.test',
|
||||
'de.example.test',
|
||||
'ice.example.test',
|
||||
'work.example.test',
|
||||
], () => 0.74);
|
||||
|
||||
assert.equal(value, 'ice.example.test');
|
||||
});
|
||||
|
||||
test('pickRandomSuffix ignores empty and duplicate suffix values', () => {
|
||||
const value = pickRandomSuffix([
|
||||
' co.example.test ',
|
||||
'',
|
||||
null,
|
||||
'de.example.test',
|
||||
'@ICE.example.test',
|
||||
'de.example.test',
|
||||
], () => 0.9);
|
||||
|
||||
assert.equal(value, 'ice.example.test');
|
||||
});
|
||||
|
||||
test('selectVerificationMessage ignores messages for other recipients', () => {
|
||||
const result = selectVerificationMessage([
|
||||
{
|
||||
combinedText: 'Your ChatGPT code is 123456',
|
||||
emailTimestamp: parseAdminTimestamp('2026/4/7 10:33:07'),
|
||||
matchedEmail: 'someone-else@co.example.test',
|
||||
messageId: '11',
|
||||
subject: 'Your ChatGPT code is 123456',
|
||||
},
|
||||
], {
|
||||
filterAfterTimestamp: 0,
|
||||
senderFilters: ['openai'],
|
||||
subjectFilters: ['code'],
|
||||
targetEmail: 'target@co.example.test',
|
||||
});
|
||||
|
||||
assert.equal(result, null);
|
||||
});
|
||||
|
||||
test('selectVerificationMessage requires a strictly newer timestamp than filterAfterTimestamp', () => {
|
||||
const ts = parseAdminTimestamp('2026/4/7 10:33:07');
|
||||
const result = selectVerificationMessage([
|
||||
{
|
||||
combinedText: 'Enter this temporary verification code to continue: 377680',
|
||||
emailTimestamp: ts,
|
||||
matchedEmail: 'target@co.example.test',
|
||||
messageId: '11',
|
||||
subject: 'Your ChatGPT code is 377680',
|
||||
},
|
||||
], {
|
||||
filterAfterTimestamp: ts,
|
||||
senderFilters: ['openai'],
|
||||
subjectFilters: ['code'],
|
||||
targetEmail: 'target@co.example.test',
|
||||
});
|
||||
|
||||
assert.equal(result, null);
|
||||
});
|
||||
|
||||
test('selectVerificationMessage picks the newest matching message after the threshold', () => {
|
||||
const result = selectVerificationMessage([
|
||||
{
|
||||
combinedText: '旧验证码 111111',
|
||||
emailTimestamp: parseAdminTimestamp('2026/4/7 10:30:00'),
|
||||
matchedEmail: 'target@co.example.test',
|
||||
messageId: '8',
|
||||
subject: 'Your ChatGPT code is 111111',
|
||||
},
|
||||
{
|
||||
combinedText: 'Enter this temporary verification code to continue: 377680',
|
||||
emailTimestamp: parseAdminTimestamp('2026/4/7 10:33:07'),
|
||||
matchedEmail: 'target@co.example.test',
|
||||
messageId: '11',
|
||||
subject: 'Your ChatGPT code is 377680',
|
||||
},
|
||||
], {
|
||||
filterAfterTimestamp: parseAdminTimestamp('2026/4/7 10:31:00'),
|
||||
senderFilters: ['openai'],
|
||||
subjectFilters: ['code'],
|
||||
targetEmail: 'target@co.example.test',
|
||||
});
|
||||
|
||||
assert.deepEqual(result, {
|
||||
code: '377680',
|
||||
emailTimestamp: parseAdminTimestamp('2026/4/7 10:33:07'),
|
||||
matchedEmail: 'target@co.example.test',
|
||||
messageId: '11',
|
||||
subject: 'Your ChatGPT code is 377680',
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const {
|
||||
DEFAULT_CLOUDFLARE_TEMP_EMAIL_ADMIN_URL,
|
||||
EMAIL_PROVIDER_DUCK,
|
||||
EMAIL_PROVIDER_CLOUDFLARE_TEMP_EMAIL,
|
||||
EMAIL_PROVIDER_RELAY_FIREFOX,
|
||||
getEmailProviderDisplayName,
|
||||
getNextRelayMaskLabel,
|
||||
isCloudflareTempEmailProvider,
|
||||
normalizeCloudflareTempEmailAdminUrl,
|
||||
normalizeEmailProvider,
|
||||
shouldUseEmailSourceForVerification,
|
||||
shouldSkipStep9Cleanup,
|
||||
} = require('../shared/email-provider.js');
|
||||
|
||||
test('normalizeEmailProvider keeps relay_firefox as-is', () => {
|
||||
assert.equal(normalizeEmailProvider('relay_firefox'), EMAIL_PROVIDER_RELAY_FIREFOX);
|
||||
});
|
||||
|
||||
test('normalizeEmailProvider keeps cloudflare_temp_email as-is', () => {
|
||||
assert.equal(
|
||||
normalizeEmailProvider('cloudflare_temp_email'),
|
||||
EMAIL_PROVIDER_CLOUDFLARE_TEMP_EMAIL
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeEmailProvider falls back to duckduckgo for unknown values', () => {
|
||||
assert.equal(normalizeEmailProvider('something-else'), EMAIL_PROVIDER_DUCK);
|
||||
});
|
||||
|
||||
test('isCloudflareTempEmailProvider identifies cloudflare_temp_email', () => {
|
||||
assert.equal(isCloudflareTempEmailProvider('cloudflare_temp_email'), true);
|
||||
});
|
||||
|
||||
test('isCloudflareTempEmailProvider rejects relay_firefox', () => {
|
||||
assert.equal(isCloudflareTempEmailProvider('relay_firefox'), false);
|
||||
});
|
||||
|
||||
test('getEmailProviderDisplayName returns Cloudflare Temp Email label', () => {
|
||||
assert.equal(
|
||||
getEmailProviderDisplayName('cloudflare_temp_email'),
|
||||
'Cloudflare Temp Email'
|
||||
);
|
||||
});
|
||||
|
||||
test('DEFAULT_CLOUDFLARE_TEMP_EMAIL_ADMIN_URL uses the public open-source-safe admin URL', () => {
|
||||
assert.equal(
|
||||
DEFAULT_CLOUDFLARE_TEMP_EMAIL_ADMIN_URL,
|
||||
'https://mail.cloudflare.com/admin'
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeCloudflareTempEmailAdminUrl falls back to the default URL for empty values', () => {
|
||||
assert.equal(
|
||||
normalizeCloudflareTempEmailAdminUrl(''),
|
||||
DEFAULT_CLOUDFLARE_TEMP_EMAIL_ADMIN_URL
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeCloudflareTempEmailAdminUrl trims whitespace and prepends https when protocol is missing', () => {
|
||||
assert.equal(
|
||||
normalizeCloudflareTempEmailAdminUrl(' custom.example.com/admin '),
|
||||
'https://custom.example.com/admin'
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeCloudflareTempEmailAdminUrl normalizes the default admin URL path', () => {
|
||||
assert.equal(
|
||||
normalizeCloudflareTempEmailAdminUrl('https://mail.cloudflare.com/admin/'),
|
||||
DEFAULT_CLOUDFLARE_TEMP_EMAIL_ADMIN_URL
|
||||
);
|
||||
});
|
||||
|
||||
test('getNextRelayMaskLabel returns t1 when there are no existing labels', () => {
|
||||
assert.equal(getNextRelayMaskLabel([]), 't1');
|
||||
});
|
||||
|
||||
test('getNextRelayMaskLabel fills the first numeric gap', () => {
|
||||
assert.equal(getNextRelayMaskLabel(['t1', 'hello', 't3']), 't2');
|
||||
});
|
||||
|
||||
test('shouldSkipStep9Cleanup returns false for relay_firefox', () => {
|
||||
assert.equal(shouldSkipStep9Cleanup('relay_firefox'), false);
|
||||
});
|
||||
|
||||
test('shouldUseEmailSourceForVerification returns true for cloudflare_temp_email', () => {
|
||||
assert.equal(shouldUseEmailSourceForVerification('cloudflare_temp_email'), true);
|
||||
});
|
||||
|
||||
test('shouldUseEmailSourceForVerification returns false for relay_firefox', () => {
|
||||
assert.equal(shouldUseEmailSourceForVerification('relay_firefox'), false);
|
||||
});
|
||||
|
||||
test('shouldUseEmailSourceForVerification returns false for duckduckgo', () => {
|
||||
assert.equal(shouldUseEmailSourceForVerification('duckduckgo'), false);
|
||||
});
|
||||
|
||||
test('shouldSkipStep9Cleanup returns true for duckduckgo', () => {
|
||||
assert.equal(shouldSkipStep9Cleanup('duckduckgo'), true);
|
||||
});
|
||||
|
||||
test('shouldSkipStep9Cleanup returns true for cloudflare_temp_email', () => {
|
||||
assert.equal(shouldSkipStep9Cleanup('cloudflare_temp_email'), true);
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const {
|
||||
hasAnyConsentPageState,
|
||||
findLoopbackCallbackUrl,
|
||||
isConsentUrl,
|
||||
isConsentPageState,
|
||||
isLoopbackCallbackUrl,
|
||||
} = require('../shared/oauth-flow.js');
|
||||
|
||||
test('isConsentUrl matches the exact known consent URL', () => {
|
||||
assert.equal(
|
||||
isConsentUrl('https://auth.openai.com/sign-in-with-chatgpt/codex/consent'),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('isConsentUrl rejects unrelated auth routes', () => {
|
||||
assert.equal(
|
||||
isConsentUrl('https://auth.openai.com/u/signup/identifier'),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test('isConsentPageState accepts sign-in-with-chatgpt routes when a continue button is visible', () => {
|
||||
assert.equal(
|
||||
isConsentPageState({
|
||||
url: 'https://auth.openai.com/sign-in-with-chatgpt/codex/consent?state=abc',
|
||||
hasVisibleContinueButton: true,
|
||||
}),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('isConsentPageState rejects sign-in-with-chatgpt routes without a visible continue button when URL is not exact', () => {
|
||||
assert.equal(
|
||||
isConsentPageState({
|
||||
url: 'https://auth.openai.com/sign-in-with-chatgpt/codex/checkpoint',
|
||||
hasVisibleContinueButton: false,
|
||||
}),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test('hasAnyConsentPageState returns true when consent appears after an initial non-consent state', () => {
|
||||
assert.equal(
|
||||
hasAnyConsentPageState([
|
||||
{
|
||||
url: 'https://auth.openai.com/u/signup/profile',
|
||||
hasVisibleContinueButton: false,
|
||||
},
|
||||
{
|
||||
url: 'https://auth.openai.com/sign-in-with-chatgpt/codex/consent?state=abc',
|
||||
hasVisibleContinueButton: true,
|
||||
},
|
||||
]),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('isLoopbackCallbackUrl accepts localhost callback URLs', () => {
|
||||
assert.equal(
|
||||
isLoopbackCallbackUrl('http://localhost:1455/auth/callback?code=abc&state=123'),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('isLoopbackCallbackUrl accepts 127.0.0.1 callback URLs', () => {
|
||||
assert.equal(
|
||||
isLoopbackCallbackUrl('http://127.0.0.1:8317/codex/callback?code=abc&state=123'),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('isLoopbackCallbackUrl rejects non-loopback callback URLs', () => {
|
||||
assert.equal(
|
||||
isLoopbackCallbackUrl('https://example.com/callback?code=abc&state=123'),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test('findLoopbackCallbackUrl returns the first loopback callback URL from candidates', () => {
|
||||
assert.equal(
|
||||
findLoopbackCallbackUrl([
|
||||
'https://auth.openai.com/sign-in-with-chatgpt/codex/consent',
|
||||
'http://127.0.0.1:8317/codex/callback?code=abc&state=123',
|
||||
'http://localhost:1455/auth/callback?code=def&state=456',
|
||||
]),
|
||||
'http://127.0.0.1:8317/codex/callback?code=abc&state=123'
|
||||
);
|
||||
});
|
||||
|
||||
test('findLoopbackCallbackUrl returns null when no loopback callback URL exists', () => {
|
||||
assert.equal(
|
||||
findLoopbackCallbackUrl([
|
||||
'https://auth.openai.com/sign-in-with-chatgpt/codex/consent',
|
||||
'https://example.com/callback?code=abc&state=123',
|
||||
]),
|
||||
null
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const {
|
||||
extractVerificationCode,
|
||||
findNewQQVerificationCode,
|
||||
} = require('../shared/qq-mail.js');
|
||||
|
||||
test('extractVerificationCode reads 6-digit codes from QQ mail text', () => {
|
||||
assert.equal(
|
||||
extractVerificationCode('你的 ChatGPT 代码为 479637,请勿泄露。'),
|
||||
'479637'
|
||||
);
|
||||
});
|
||||
|
||||
test('findNewQQVerificationCode rejects matching emails that already existed before polling', () => {
|
||||
const result = findNewQQVerificationCode([
|
||||
{
|
||||
mailId: 'old-1',
|
||||
sender: 'OpenAI',
|
||||
subject: '你的 ChatGPT 代码为 479637',
|
||||
digest: '用于验证你的邮箱地址',
|
||||
},
|
||||
], {
|
||||
existingMailIds: ['old-1'],
|
||||
senderFilters: ['openai', 'verify'],
|
||||
subjectFilters: ['code', '验证'],
|
||||
});
|
||||
|
||||
assert.equal(result, null);
|
||||
});
|
||||
|
||||
test('findNewQQVerificationCode accepts the first new matching email', () => {
|
||||
const result = findNewQQVerificationCode([
|
||||
{
|
||||
mailId: 'old-1',
|
||||
sender: 'OpenAI',
|
||||
subject: '你的 ChatGPT 代码为 111111',
|
||||
digest: '旧邮件',
|
||||
},
|
||||
{
|
||||
mailId: 'new-1',
|
||||
sender: 'OpenAI',
|
||||
subject: '你的 ChatGPT 代码为 222222',
|
||||
digest: '新邮件',
|
||||
},
|
||||
], {
|
||||
existingMailIds: ['old-1'],
|
||||
senderFilters: ['openai', 'verify'],
|
||||
subjectFilters: ['code', '验证'],
|
||||
});
|
||||
|
||||
assert.deepEqual(result, {
|
||||
code: '222222',
|
||||
mailId: 'new-1',
|
||||
source: 'new',
|
||||
subject: '你的 ChatGPT 代码为 222222',
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user