mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
fake route for oculus
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
|||||||
CachedLogin,
|
CachedLogin,
|
||||||
ChangePasswordRequest,
|
ChangePasswordRequest,
|
||||||
ChangePasswordResponse,
|
ChangePasswordResponse,
|
||||||
|
FakeCachedLogin,
|
||||||
form,
|
form,
|
||||||
json,
|
json,
|
||||||
OAuthError,
|
OAuthError,
|
||||||
@@ -58,6 +59,18 @@ const PLATFORM_TYPES: Record<number, string> = {
|
|||||||
8: 'Pico',
|
8: 'Pico',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** PlatformType for Oculus, which `/cachedlogin/forplatformid` currently stubs out. */
|
||||||
|
const OCULUS_PLATFORM = 1
|
||||||
|
|
||||||
|
/** The canned entry served for any Oculus cached-login lookup. See the route below. */
|
||||||
|
const FAKE_OCULUS_CACHED_LOGIN = {
|
||||||
|
platform: OCULUS_PLATFORM,
|
||||||
|
platformId: '1',
|
||||||
|
accountId: 1,
|
||||||
|
lastLoginTime: '2026-07-19T17:13:29.225Z',
|
||||||
|
requirePassword: true,
|
||||||
|
} as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signup caps, enforced on create_account only (never on login — an existing account
|
* Signup caps, enforced on create_account only (never on login — an existing account
|
||||||
* always stays reachable, however many accounts its owner has since accumulated).
|
* always stays reachable, however many accounts its owner has since accumulated).
|
||||||
@@ -254,7 +267,9 @@ const app = new Hono<App>()
|
|||||||
'Accounts the client may offer on its login screen for this platform identity. ' +
|
'Accounts the client may offer on its login screen for this platform identity. ' +
|
||||||
'Filtered to those a `cached_login` grant would actually accept, so an entry here ' +
|
'Filtered to those a `cached_login` grant would actually accept, so an entry here ' +
|
||||||
'is always redeemable. An unknown id yields `[]` (not a 404) and the client falls ' +
|
'is always redeemable. An unknown id yields `[]` (not a 404) and the client falls ' +
|
||||||
'back to a fresh login or create_account.',
|
'back to a fresh login or create_account. ' +
|
||||||
|
'EXCEPT platform 1 (Oculus), which is stubbed: it ignores the id and returns one ' +
|
||||||
|
'canned, non-redeemable entry with `requirePassword: true`.',
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: 'platform',
|
name: 'platform',
|
||||||
@@ -271,12 +286,23 @@ const app = new Hono<App>()
|
|||||||
schema: { type: 'string' },
|
schema: { type: 'string' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
responses: { 200: json(CachedLogin.array(), 'Matching accounts; `[]` if none') },
|
responses: {
|
||||||
|
200: json(
|
||||||
|
CachedLogin.or(FakeCachedLogin).array(),
|
||||||
|
'Matching accounts; `[]` if none. The canned entry for platform 1 (Oculus).'
|
||||||
|
),
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const { platform, id } = c.req.param()
|
const { platform, id } = c.req.param()
|
||||||
logger.info('cached login lookup', { platform, id })
|
logger.info('cached login lookup', { platform, id })
|
||||||
const platformInt = Number.parseInt(platform, 10)
|
const platformInt = Number.parseInt(platform, 10)
|
||||||
|
// Oculus has no identity flow yet, so there is nothing in the DB to look up and
|
||||||
|
// the real path would always yield []. Hand back one canned entry instead, so the
|
||||||
|
// Oculus client gets past its login screen. `requirePassword` is true — unlike a
|
||||||
|
// genuine cached login there is no platform ticket behind this, so the client must
|
||||||
|
// prompt. Delete this branch once Oculus platform auth lands.
|
||||||
|
if (platformInt === OCULUS_PLATFORM) return c.json([FAKE_OCULUS_CACHED_LOGIN])
|
||||||
const accounts = await getAccountsByPlatformId(c.env.DB, id)
|
const accounts = await getAccountsByPlatformId(c.env.DB, id)
|
||||||
// Offer only accounts the `cached_login` grant will actually accept — same check.
|
// Offer only accounts the `cached_login` grant will actually accept — same check.
|
||||||
return c.json(
|
return c.json(
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ export const CachedLogin = z.object({
|
|||||||
.describe('Always false — platform ownership is the credential for a cached login'),
|
.describe('Always false — platform ownership is the credential for a cached login'),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stubbed Oculus cached login. Same shape as `CachedLogin`, but `requirePassword`
|
||||||
|
* is true — nothing proves platform ownership, so the client has to prompt.
|
||||||
|
*/
|
||||||
|
export const FakeCachedLogin = CachedLogin.extend({
|
||||||
|
requirePassword: z.literal(true).describe('Always true — the entry is not platform-backed'),
|
||||||
|
})
|
||||||
|
|
||||||
/** OAuth-shaped error body. Always HTTP 400 except `server_error` (500). */
|
/** OAuth-shaped error body. Always HTTP 400 except `server_error` (500). */
|
||||||
export const OAuthError = z.object({
|
export const OAuthError = z.object({
|
||||||
error: z.enum(['invalid_grant', 'invalid_request', 'server_error']),
|
error: z.enum(['invalid_grant', 'invalid_request', 'server_error']),
|
||||||
|
|||||||
@@ -117,12 +117,28 @@ describe('auth worker routes', () => {
|
|||||||
expect(await res.text()).toBe('"AA=="')
|
expect(await res.text()).toBe('"AA=="')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Platform 0 (Steam), not 1 — platform 1 is Oculus, which is stubbed below.
|
||||||
test('GET /cachedlogin/forplatformid/:platform/:id returns [] (no cached login)', async () => {
|
test('GET /cachedlogin/forplatformid/:platform/:id returns [] (no cached login)', async () => {
|
||||||
const res = await exports.default.fetch(`${ORIGIN}/cachedlogin/forplatformid/1/abc123`)
|
const res = await exports.default.fetch(`${ORIGIN}/cachedlogin/forplatformid/0/abc123`)
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(await res.json()).toEqual([])
|
expect(await res.json()).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Oculus is stubbed: no DB lookup, one canned entry whatever the id.
|
||||||
|
test('GET /cachedlogin/forplatformid/1/:id returns the canned Oculus entry', async () => {
|
||||||
|
const res = await exports.default.fetch(`${ORIGIN}/cachedlogin/forplatformid/1/anything`)
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(await res.json()).toEqual([
|
||||||
|
{
|
||||||
|
platform: 1,
|
||||||
|
platformId: '1',
|
||||||
|
accountId: 1,
|
||||||
|
lastLoginTime: '2026-07-19T17:13:29.225Z',
|
||||||
|
requirePassword: true,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
// Only Steam (platform 0) can be verified (via its signed platform_auth ticket),
|
// Only Steam (platform 0) can be verified (via its signed platform_auth ticket),
|
||||||
// so every OTHER platform is rejected on the platform-authenticated grants — we
|
// so every OTHER platform is rejected on the platform-authenticated grants — we
|
||||||
// won't bind or authorize an identity we can't prove.
|
// won't bind or authorize an identity we can't prove.
|
||||||
|
|||||||
Generated
+2
-2
@@ -688,7 +688,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/hono-helpers
|
version: link:../../packages/hono-helpers
|
||||||
'@scalar/api-reference':
|
'@scalar/api-reference':
|
||||||
specifier: ^1.63.0
|
specifier: 1.63.0
|
||||||
version: 1.63.0(tailwindcss@4.3.3)(typescript@6.0.3)(zod@4.4.3)
|
version: 1.63.0(tailwindcss@4.3.3)(typescript@6.0.3)(zod@4.4.3)
|
||||||
hono:
|
hono:
|
||||||
specifier: 4.12.27
|
specifier: 4.12.27
|
||||||
@@ -4440,7 +4440,7 @@ snapshots:
|
|||||||
'@floating-ui/vue@1.1.9(vue@3.5.40(typescript@6.0.3))':
|
'@floating-ui/vue@1.1.9(vue@3.5.40(typescript@6.0.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@floating-ui/dom': 1.8.0
|
'@floating-ui/dom': 1.8.0
|
||||||
'@floating-ui/utils': 0.2.10
|
'@floating-ui/utils': 0.2.12
|
||||||
vue-demi: 0.14.10(vue@3.5.40(typescript@6.0.3))
|
vue-demi: 0.14.10(vue@3.5.40(typescript@6.0.3))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
|
|||||||
Reference in New Issue
Block a user