-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathSSOTauri.test.ts
More file actions
109 lines (93 loc) · 3.73 KB
/
Copy pathSSOTauri.test.ts
File metadata and controls
109 lines (93 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { type as osType } from '@tauri-apps/plugin-os';
import {
buildTauriSsoRedirectUrl,
parseTauriOidcCallback,
parseTauriSsoCallback,
rememberTauriSsoNonce,
takeTauriSsoNonce,
} from './SSOTauri';
vi.mock('@tauri-apps/plugin-os', () => ({
type: vi.fn<() => string>(() => 'android'),
}));
beforeEach(() => {
vi.unstubAllEnvs();
vi.mocked(osType).mockReturnValue('android');
localStorage.clear();
});
describe('buildTauriSsoRedirectUrl', () => {
it('uses the registered deep-link callback in production desktop builds', () => {
vi.stubEnv('DEV', false);
vi.mocked(osType).mockReturnValue('linux');
const url = new URL(buildTauriSsoRedirectUrl('https://hs.example'));
expect(url.protocol).toBe('sable:');
expect(url.hostname).toBe('login');
expect(url.pathname).toBe('/lp/sso-callback');
expect(url.searchParams.get('server')).toBe('https://hs.example');
const nonce = url.searchParams.get('sso_nonce');
expect(nonce).toBeTruthy();
expect(takeTauriSsoNonce()).toBe(nonce);
expect(takeTauriSsoNonce()).toBeUndefined();
});
it('embeds the server and stores the same nonce it puts in the url', () => {
const url = new URL(buildTauriSsoRedirectUrl('https://hs.example'));
expect(url.searchParams.get('server')).toBe('https://hs.example');
const nonce = url.searchParams.get('sso_nonce');
expect(nonce).toBeTruthy();
expect(takeTauriSsoNonce()).toBe(nonce);
});
it('omits the server when none is provided but still sets a nonce', () => {
const url = new URL(buildTauriSsoRedirectUrl());
expect(url.searchParams.get('server')).toBeNull();
expect(url.searchParams.get('sso_nonce')).toBeTruthy();
});
});
describe('takeTauriSsoNonce', () => {
it('returns the stored nonce once, then undefined', () => {
rememberTauriSsoNonce('abc');
expect(takeTauriSsoNonce()).toBe('abc');
expect(takeTauriSsoNonce()).toBeUndefined();
});
});
describe('parseTauriSsoCallback', () => {
it('round-trips loginToken, server and nonce from a built redirect', () => {
const redirect = buildTauriSsoRedirectUrl('https://hs.example');
const nonce = takeTauriSsoNonce();
expect(parseTauriSsoCallback(`${redirect}&loginToken=tok_123`)).toEqual({
loginToken: 'tok_123',
server: 'https://hs.example',
nonce,
});
});
it('rejects the wrong protocol', () => {
expect(parseTauriSsoCallback('https://login/lp/sso-callback?loginToken=x')).toBeUndefined();
});
it('rejects a missing loginToken', () => {
expect(parseTauriSsoCallback('sable://login/lp/sso-callback?server=x')).toBeUndefined();
});
});
describe('parseTauriOidcCallback', () => {
it('parses code and state from single-slash format', () => {
expect(parseTauriOidcCallback('moe.sable.app:/login?code=c1&state=s1')).toEqual({
code: 'c1',
state: 's1',
});
});
it('parses code and state from authority/hostname format (moe.sable.app://login)', () => {
expect(parseTauriOidcCallback('moe.sable.app://login?code=c1&state=s1')).toEqual({
code: 'c1',
state: 's1',
});
});
it('rejects the wrong path', () => {
expect(parseTauriOidcCallback('moe.sable.app:/other?code=c1&state=s1')).toBeUndefined();
expect(parseTauriOidcCallback('moe.sable.app://other?code=c1&state=s1')).toBeUndefined();
});
it('rejects a different protocol', () => {
expect(parseTauriOidcCallback('sable://login?code=c1&state=s1')).toBeUndefined();
expect(parseTauriOidcCallback('https://login?code=c1&state=s1')).toBeUndefined();
});
it('rejects an unrelated hostname with a login path', () => {
expect(parseTauriOidcCallback('moe.sable.app://evil/login?code=c1&state=s1')).toBeUndefined();
});
});