Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 changed files with 3442369 additions and 0 deletions
+277
View File
@@ -0,0 +1,277 @@
/**
* Tests for electron/native-oauth.ts — the pure RFC 8252 native-app login
* helpers (PKCE, capability detection, URL building, loopback callback
* parsing, token-response normalization, refresh-timing).
*
* Run with: node --test electron/native-oauth.test.ts
* (Wired into the vitest `electron` project via electron/**\/*.test.ts.)
*/
import assert from 'node:assert/strict'
import { createHash } from 'node:crypto'
import { test } from 'vitest'
import {
buildNativeAuthorizeUrl,
generatePkcePair,
generateState,
NATIVE_FLOW_ID,
nativeRefreshUrl,
nativeTokenUrl,
parseLoopbackCallback,
parseStoredTokenSet,
parseTokenResponse,
resolveLoginStrategy,
statusSupportsNativeFlow,
tokenNeedsRefresh
} from './native-oauth'
// --- PKCE ---
test('generatePkcePair produces a valid S256 verifier/challenge', () => {
const pair = generatePkcePair()
assert.equal(pair.method, 'S256')
// Verifier length within RFC 7636 range (43128).
assert.ok(pair.verifier.length >= 43 && pair.verifier.length <= 128)
// Challenge must be the base64url SHA-256 of the verifier.
const expected = createHash('sha256')
.update(pair.verifier, 'ascii')
.digest('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
assert.equal(pair.challenge, expected)
// No padding / URL-unsafe chars.
assert.doesNotMatch(pair.verifier, /[+/=]/)
assert.doesNotMatch(pair.challenge, /[+/=]/)
})
test('generatePkcePair is unique per call', () => {
assert.notEqual(generatePkcePair().verifier, generatePkcePair().verifier)
})
test('generateState is non-empty and URL-safe', () => {
const s = generateState()
assert.ok(s.length > 0)
assert.doesNotMatch(s, /[+/=]/)
})
// --- capability detection ---
test('statusSupportsNativeFlow reads the auth_flows array', () => {
assert.equal(statusSupportsNativeFlow({ auth_flows: ['cookie', NATIVE_FLOW_ID] }), true)
assert.equal(statusSupportsNativeFlow({ auth_flows: ['cookie'] }), false)
// Older gateway: no auth_flows field at all ⇒ not supported.
assert.equal(statusSupportsNativeFlow({ auth_required: true }), false)
assert.equal(statusSupportsNativeFlow({}), false)
assert.equal(statusSupportsNativeFlow(null), false)
// Malformed field shapes never throw.
assert.equal(statusSupportsNativeFlow({ auth_flows: 'native_pkce' }), false)
})
test('resolveLoginStrategy picks native only when advertised and not forced', () => {
const gated = { auth_required: true, auth_flows: ['cookie', 'native_pkce'] }
const legacy = { auth_required: true, auth_flows: ['cookie'] }
assert.equal(resolveLoginStrategy(gated), 'native')
// Compatibility fallback: an older gateway lacking native_pkce ⇒ embedded.
assert.equal(resolveLoginStrategy(legacy), 'embedded')
// A user/env override can pin the legacy flow even on a capable gateway.
assert.equal(resolveLoginStrategy(gated, { forceEmbedded: true }), 'embedded')
})
// --- provider-aware strategy ---
test('resolveLoginStrategy returns embedded when every provider supports password', () => {
const statusBody = { auth_required: true, auth_flows: ['cookie', 'native_pkce'] }
const providers = [{ name: 'basic', supportsPassword: true }]
assert.equal(resolveLoginStrategy(statusBody, { providers }), 'embedded')
})
test('resolveLoginStrategy returns embedded for all-password even without native_pkce in auth_flows', () => {
const statusBody = { auth_required: true, auth_flows: ['cookie'] }
const providers = [{ name: 'basic', supportsPassword: true }]
assert.equal(resolveLoginStrategy(statusBody, { providers }), 'embedded')
})
test('resolveLoginStrategy returns native for native_pkce gateway with non-password provider', () => {
const statusBody = { auth_required: true, auth_flows: ['cookie', 'native_pkce'] }
const providers = [{ name: 'nous', displayName: 'Nous Research', supportsPassword: false }]
assert.equal(resolveLoginStrategy(statusBody, { providers }), 'native')
})
test('resolveLoginStrategy returns native for a mixed provider deployment', () => {
const statusBody = { auth_required: true, auth_flows: ['cookie', 'native_pkce'] }
const providers = [
{ name: 'basic', supportsPassword: true },
{ name: 'nous', supportsPassword: false }
]
assert.equal(resolveLoginStrategy(statusBody, { providers }), 'native')
})
test('resolveLoginStrategy preserves existing behavior when providers are empty or missing', () => {
const gated = { auth_required: true, auth_flows: ['cookie', 'native_pkce'] }
const legacy = { auth_required: true, auth_flows: ['cookie'] }
assert.equal(resolveLoginStrategy(gated, {}), 'native')
assert.equal(resolveLoginStrategy(gated, { providers: [] }), 'native')
assert.equal(resolveLoginStrategy(legacy, {}), 'embedded')
assert.equal(resolveLoginStrategy(legacy, { providers: [] }), 'embedded')
})
test('resolveLoginStrategy ignores providers with no name', () => {
const statusBody = { auth_required: true, auth_flows: ['cookie', 'native_pkce'] }
const providers = [{ supportsPassword: true }]
// The unnamed provider is filtered out — still falls through to auth_flows.
assert.equal(resolveLoginStrategy(statusBody, { providers }), 'native')
})
// --- URL building ---
test('buildNativeAuthorizeUrl encodes params and honours a path prefix', () => {
const url = buildNativeAuthorizeUrl('https://gw.example.com', {
challenge: 'CHAL',
redirectUri: 'http://127.0.0.1:51000/callback',
state: 'STATE',
provider: 'nous'
})
const parsed = new URL(url)
assert.equal(parsed.origin, 'https://gw.example.com')
assert.equal(parsed.pathname, '/auth/native/authorize')
assert.equal(parsed.searchParams.get('code_challenge'), 'CHAL')
assert.equal(parsed.searchParams.get('code_challenge_method'), 'S256')
assert.equal(parsed.searchParams.get('redirect_uri'), 'http://127.0.0.1:51000/callback')
assert.equal(parsed.searchParams.get('state'), 'STATE')
assert.equal(parsed.searchParams.get('provider'), 'nous')
})
test('buildNativeAuthorizeUrl omits provider when not given and preserves prefix', () => {
const url = buildNativeAuthorizeUrl('https://gw.example.com/hermes', {
challenge: 'C',
redirectUri: 'http://127.0.0.1:1/cb',
state: 'S'
})
const parsed = new URL(url)
assert.equal(parsed.pathname, '/hermes/auth/native/authorize')
assert.equal(parsed.searchParams.get('provider'), null)
})
test('nativeTokenUrl / nativeRefreshUrl build the right endpoints', () => {
assert.equal(nativeTokenUrl('https://gw.example.com'), 'https://gw.example.com/auth/native/token')
assert.equal(nativeRefreshUrl('https://gw.example.com/hermes'), 'https://gw.example.com/hermes/auth/native/refresh')
})
// --- loopback callback parsing ---
test('parseLoopbackCallback returns the code on a state match', () => {
const { code } = parseLoopbackCallback('/callback?code=abc123&state=xyz', 'xyz')
assert.equal(code, 'abc123')
})
test('parseLoopbackCallback throws on state mismatch (CSRF)', () => {
assert.throws(() => parseLoopbackCallback('/callback?code=abc&state=attacker', 'expected'), /state mismatch/i)
})
test('parseLoopbackCallback surfaces a gateway error param', () => {
assert.throws(
() => parseLoopbackCallback('/callback?error=access_denied&error_description=nope', 'xyz'),
/access_denied.*nope/i
)
})
test('parseLoopbackCallback throws when the code is absent', () => {
assert.throws(() => parseLoopbackCallback('/callback?state=xyz', 'xyz'), /missing authorization code/i)
})
// --- token response normalization ---
test('parseTokenResponse maps a well-formed body', () => {
const t = parseTokenResponse({
access_token: 'AT',
refresh_token: 'RT',
token_type: 'Bearer',
expires_at: 1893456000,
provider: 'nous',
user_id: 'u-1'
})
assert.equal(t.accessToken, 'AT')
assert.equal(t.refreshToken, 'RT')
assert.equal(t.expiresAt, 1893456000)
assert.equal(t.provider, 'nous')
assert.equal(t.userId, 'u-1')
})
test('parseTokenResponse throws on a missing access token', () => {
assert.throws(() => parseTokenResponse({ refresh_token: 'RT' }), /missing access_token/i)
})
test('parseTokenResponse tolerates an absent refresh token / expiry', () => {
const t = parseTokenResponse({ access_token: 'AT' })
assert.equal(t.refreshToken, '')
assert.equal(t.expiresAt, 0)
})
test('parseStoredTokenSet maps the encrypted on-disk camelCase shape', () => {
const t = parseStoredTokenSet({
accessToken: 'AT-stored',
refreshToken: 'RT-stored',
expiresAt: 1893456000,
provider: 'self-hosted',
userId: 'u-stored'
})
assert.equal(t.accessToken, 'AT-stored')
assert.equal(t.refreshToken, 'RT-stored')
assert.equal(t.expiresAt, 1893456000)
assert.equal(t.provider, 'self-hosted')
assert.equal(t.userId, 'u-stored')
})
test('parseTokenResponse cannot read a persisted set (the reload bug #73271)', () => {
// Guards against regressing to the wrong parser on the reload path: a
// persisted camelCase set has no snake_case access_token, so the raw-response
// parser throws — which is exactly why the stored path must use
// parseStoredTokenSet instead.
const persisted = JSON.parse(
JSON.stringify({ accessToken: 'AT', refreshToken: 'RT', expiresAt: 1, provider: 'nous', userId: 'u' })
)
assert.throws(() => parseTokenResponse(persisted), /missing access_token/i)
assert.equal(parseStoredTokenSet(persisted).accessToken, 'AT')
})
test('parseStoredTokenSet rejects a non-normalized server response', () => {
assert.throws(() => parseStoredTokenSet({ access_token: 'AT-server' }), /missing accessToken/i)
})
// --- refresh timing ---
test('tokenNeedsRefresh respects the skew window', () => {
const now = 1_000_000
// Expires comfortably in the future ⇒ no refresh.
assert.equal(tokenNeedsRefresh({ expiresAt: now + 3600 }, now), false)
// Within the 60s skew ⇒ refresh early.
assert.equal(tokenNeedsRefresh({ expiresAt: now + 30 }, now), true)
// Already expired ⇒ refresh.
assert.equal(tokenNeedsRefresh({ expiresAt: now - 10 }, now), true)
// Unknown expiry ⇒ refresh (validate before use).
assert.equal(tokenNeedsRefresh({ expiresAt: 0 }, now), true)
})