52 lines
2.9 KiB
JavaScript
52 lines
2.9 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { EventEmitter } = require('node:events');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { allowedSonyUrl, createSonyBrowserAuthentication } = require('../../src/ipc/trophy-history');
|
|
|
|
class FakeWindow extends EventEmitter {
|
|
constructor(options) {
|
|
super(); this.options = options; this.destroyed = false; this.shown = false;
|
|
const contents = new EventEmitter();
|
|
contents.session = { fetch: async () => ({ ok: true, json: async () => ({ npsso: 'n'.repeat(64) }) }), clearStorageData: async () => { this.storageCleared = true; }, clearCache: async () => { this.cacheCleared = true; } };
|
|
contents.setWindowOpenHandler = handler => { this.openHandler = handler; };
|
|
this.webContents = contents;
|
|
FakeWindow.latest = this;
|
|
}
|
|
loadURL(url) { this.url = url; queueMicrotask(() => this.webContents.emit('did-finish-load')); return Promise.resolve(); }
|
|
show() { this.shown = true; }
|
|
isDestroyed() { return this.destroyed; }
|
|
destroy() { this.destroyed = true; this.emit('closed'); }
|
|
}
|
|
|
|
test('Sony browser authentication uses an ephemeral hardened window and clears it after token exchange', async () => {
|
|
let received = null;
|
|
const authenticate = createSonyBrowserAuthentication({ BrowserWindow: FakeWindow, parent: {}, timeoutMs: 1000, randomBytes: () => Buffer.alloc(12, 7), authenticate: async input => { received = input; return { configured: true }; } });
|
|
const result = await authenticate();
|
|
assert.equal(result.configured, true); assert.equal(result.temporaryBrowserDataCleared, true);
|
|
assert.equal(received.npsso, 'n'.repeat(64));
|
|
assert.equal(FakeWindow.latest.options.webPreferences.partition.startsWith('persist:'), false);
|
|
assert.equal(FakeWindow.latest.options.webPreferences.nodeIntegration, false);
|
|
assert.equal(FakeWindow.latest.options.webPreferences.contextIsolation, true);
|
|
assert.equal(FakeWindow.latest.storageCleared, true); assert.equal(FakeWindow.latest.cacheCleared, true);
|
|
});
|
|
|
|
test('browser authentication allowlists only HTTPS Sony and PlayStation origins', () => {
|
|
assert.equal(allowedSonyUrl('https://ca.account.sony.com/api/v1/ssocookie'), true);
|
|
assert.equal(allowedSonyUrl('https://www.playstation.com/'), true);
|
|
assert.equal(allowedSonyUrl('http://www.playstation.com/'), false);
|
|
assert.equal(allowedSonyUrl('https://playstation.com.attacker.example/'), false);
|
|
});
|
|
|
|
test('desktop registration exposes automated authentication but blocks it from the web bridge', () => {
|
|
const root = path.resolve(__dirname, '../..');
|
|
const main = fs.readFileSync(path.join(root, 'main.js'), 'utf8');
|
|
const preload = fs.readFileSync(path.join(root, 'preload.js'), 'utf8');
|
|
assert.match(main, /_registerTrophyHistory\(ipcMain/);
|
|
assert.match(main, /WEB_BLOCKED_CHANNELS[\s\S]*trophy:history-import:browser-authenticate/);
|
|
assert.match(preload, /trophyHistoryBrowserAuthenticate/);
|
|
});
|