154 lines
4.5 KiB
TypeScript
154 lines
4.5 KiB
TypeScript
import fs from 'fs-extra';
|
|
import { mkdtempSync, rmSync } from 'fs';
|
|
import path from 'path';
|
|
import { tmpdir } from 'os';
|
|
import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
|
|
let tempHome: string | undefined;
|
|
let originalHome: string | undefined;
|
|
|
|
async function loadWebLogin() {
|
|
vi.resetModules();
|
|
tempHome = mkdtempSync(path.join(tmpdir(), 'pinme-web-login-home-'));
|
|
originalHome = process.env.HOME;
|
|
process.env.HOME = tempHome;
|
|
vi.doMock('os', () => ({
|
|
homedir: () => tempHome,
|
|
default: {
|
|
homedir: () => tempHome,
|
|
},
|
|
}));
|
|
vi.doMock('node:os', () => ({
|
|
homedir: () => tempHome,
|
|
default: {
|
|
homedir: () => tempHome,
|
|
},
|
|
}));
|
|
return import('../../bin/utils/webLogin');
|
|
}
|
|
|
|
describe('webLogin', () => {
|
|
afterEach(() => {
|
|
vi.doUnmock('os');
|
|
vi.doUnmock('node:os');
|
|
if (originalHome === undefined) {
|
|
delete process.env.HOME;
|
|
} else {
|
|
process.env.HOME = originalHome;
|
|
}
|
|
originalHome = undefined;
|
|
if (tempHome) {
|
|
rmSync(tempHome, { recursive: true, force: true });
|
|
tempHome = undefined;
|
|
}
|
|
});
|
|
|
|
test('stores and reads auth tokens with auth headers', async () => {
|
|
const { setAuthToken, getAuthConfig, getAuthHeaders } = await loadWebLogin();
|
|
|
|
expect(setAuthToken('0xabc-jwt-token')).toEqual({
|
|
address: '0xabc',
|
|
token: 'jwt-token',
|
|
});
|
|
expect(getAuthConfig()).toEqual({
|
|
address: '0xabc',
|
|
token: 'jwt-token',
|
|
});
|
|
expect(getAuthHeaders()).toEqual({
|
|
'token-address': '0xabc',
|
|
'authentication-tokens': 'jwt-token',
|
|
});
|
|
|
|
expect(getAuthConfig()).toMatchObject({ address: '0xabc' });
|
|
});
|
|
|
|
test('trims address and token content before storing auth', async () => {
|
|
const { setAuthToken, getAuthConfig, getAuthHeaders } = await loadWebLogin();
|
|
|
|
expect(setAuthToken(' 0xabc - jwt-token ')).toEqual({
|
|
address: '0xabc',
|
|
token: 'jwt-token',
|
|
});
|
|
expect(getAuthConfig()).toEqual({
|
|
address: '0xabc',
|
|
token: 'jwt-token',
|
|
});
|
|
expect(getAuthHeaders()).toEqual({
|
|
'token-address': '0xabc',
|
|
'authentication-tokens': 'jwt-token',
|
|
});
|
|
});
|
|
|
|
test('rejects malformed combined auth tokens', async () => {
|
|
const { setAuthToken } = await loadWebLogin();
|
|
|
|
expect(() => setAuthToken('-jwt-token')).toThrow(
|
|
/Address or token is empty|Invalid token/,
|
|
);
|
|
expect(() => setAuthToken('0xabc-')).toThrow(/Invalid token format/);
|
|
expect(() => setAuthToken('missingdash')).toThrow(/Invalid token format/);
|
|
expect(() => setAuthToken(' -jwt-token')).toThrow(
|
|
'Invalid token content. Address or token is empty.',
|
|
);
|
|
expect(() => setAuthToken('0xabc- ')).toThrow(
|
|
'Invalid token content. Address or token is empty.',
|
|
);
|
|
});
|
|
|
|
test('clears auth tokens and makes headers unavailable', async () => {
|
|
const { setAuthToken, clearAuthToken, getAuthConfig, getAuthHeaders } =
|
|
await loadWebLogin();
|
|
|
|
setAuthToken('0xabc-jwt-token');
|
|
clearAuthToken();
|
|
|
|
expect(getAuthConfig()).toBeNull();
|
|
expect(() => getAuthHeaders()).toThrow('Auth not set. Run: pinme login');
|
|
});
|
|
|
|
test('getAuthConfig returns null for malformed or incomplete auth files', async () => {
|
|
const { getAuthConfig } = await loadWebLogin();
|
|
const authDir = path.join(tempHome!, '.pinme');
|
|
const authFile = path.join(authDir, 'auth.json');
|
|
fs.ensureDirSync(authDir);
|
|
|
|
fs.writeJsonSync(authFile, { address: '0xabc' });
|
|
expect(getAuthConfig()).toBeNull();
|
|
|
|
fs.writeFileSync(authFile, '{bad');
|
|
expect(getAuthConfig()).toBeNull();
|
|
});
|
|
|
|
test('login delegates to the singleton web login manager', async () => {
|
|
const { login, webLoginManager } = await loadWebLogin();
|
|
const authConfig = { address: '0xabc', token: 'jwt-token' };
|
|
const spy = vi
|
|
.spyOn(webLoginManager, 'login')
|
|
.mockResolvedValue(authConfig);
|
|
|
|
try {
|
|
await expect(login()).resolves.toBe(authConfig);
|
|
} finally {
|
|
spy.mockRestore();
|
|
}
|
|
});
|
|
|
|
test('logout clears auth and reports success', async () => {
|
|
const { setAuthToken, logout, getAuthConfig } = await loadWebLogin();
|
|
const messages: string[] = [];
|
|
const spy = vi.spyOn(console, 'log').mockImplementation((value = '') => {
|
|
messages.push(String(value));
|
|
});
|
|
|
|
try {
|
|
setAuthToken('0xabc-jwt-token');
|
|
await logout();
|
|
} finally {
|
|
spy.mockRestore();
|
|
}
|
|
|
|
expect(getAuthConfig()).toBeNull();
|
|
expect(messages.join('\n')).toContain('Logged out successfully');
|
|
});
|
|
});
|