Skip to content

Commit 5085e05

Browse files
meesvandongenMees van Dongen
authored andcommitted
fix(sevice-worker): add URL normalization for getCurrentDatabaseDomain endpoints comparison (release) (#1196)
Co-authored-by: Mees van Dongen <mvandongen@ilionx.com>
1 parent 77361cf commit 5085e05

File tree

2 files changed

+313
-174
lines changed

2 files changed

+313
-174
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,155 @@
11
import { describe, expect, it } from 'vitest';
22

33
import { openidWellknownUrlEndWith } from '../../constants';
4-
import { checkDomain, getCurrentDatabaseDomain } from '..';
5-
import { Database, OidcServerConfiguration, Tokens, TrustedDomains } from './../../types';
4+
import { checkDomain, getCurrentDatabaseDomain, normalizeUrl } from '..';
5+
import { Database, Tokens, TrustedDomains } from './../../types';
66

77
describe('domains', () => {
8-
describe('can check domain matches', () => {
9-
it('can check string domains and return void', () => {
10-
const result = () =>
11-
checkDomain(
12-
['https://securesite.com:3000'],
13-
'https://securesite.com:3000',
14-
);
15-
expect(result()).toBeUndefined();
16-
});
8+
describe('can check domain matches', () => {
9+
it('can check string domains and return void', () => {
10+
const result = () =>
11+
checkDomain(['https://securesite.com:3000'], 'https://securesite.com:3000');
12+
expect(result()).toBeUndefined();
13+
});
1714

18-
it('can check regExp domains and return void when valid', () => {
19-
const result = () =>
20-
checkDomain(
21-
[/^https:\/\/securesite\.com/],
22-
'https://securesite.com:3000',
23-
);
24-
expect(result()).toBeUndefined();
25-
});
15+
it('can check regExp domains and return void when valid', () => {
16+
const result = () =>
17+
checkDomain([/^https:\/\/securesite\.com/], 'https://securesite.com:3000');
18+
expect(result()).toBeUndefined();
19+
});
2620

27-
it('will throw error when domain is not trusted', () => {
28-
const result = () =>
29-
checkDomain(
30-
['https://notsecuresite.com'],
31-
'https://securesite.com:3000',
32-
);
33-
expect(result).toThrowError();
34-
});
21+
it('will throw error when domain is not trusted', () => {
22+
const result = () =>
23+
checkDomain(['https://notsecuresite.com'], 'https://securesite.com:3000');
24+
expect(result).toThrowError();
25+
});
3526

36-
it('will return void when endpoint is falsy', () => {
37-
const result = () => checkDomain(['https://securesite.com:3000'], '');
38-
expect(result()).toBeUndefined();
39-
});
40-
});
41-
describe('getCurrentDatabaseDomain', () => {
42-
const db: Database = {
43-
default: {
44-
configurationName: 'config',
45-
tokens: {} as Tokens,
46-
status: 'NOT_CONNECTED',
47-
state: null,
48-
codeVerifier: null,
49-
nonce: null,
50-
oidcServerConfiguration: {} as OidcServerConfiguration,
51-
hideAccessToken: true,
52-
convertAllRequestsToCorsExceptNavigate: false,
53-
setAccessTokenToNavigateRequests: true,
54-
demonstratingProofOfPossessionNonce: null,
55-
demonstratingProofOfPossessionJwkJson: null,
56-
},
57-
};
27+
it('will return void when endpoint is falsy', () => {
28+
const result = () => checkDomain(['https://securesite.com:3000'], '');
29+
expect(result()).toBeUndefined();
30+
});
31+
});
32+
describe('getCurrentDatabaseDomain', () => {
33+
const db: Database = {
34+
default: {
35+
configurationName: 'config',
36+
tokens: {} as Tokens,
37+
status: 'NOT_CONNECTED',
38+
state: null,
39+
codeVerifier: null,
40+
nonce: null,
41+
oidcServerConfiguration: {
42+
authorizationEndpoint: 'https://demo.duendesoftware.com/connect/authorize',
43+
issuer: 'https://demo.duendesoftware.com',
44+
revocationEndpoint: 'https://demo.duendesoftware.com/connect/revocation',
45+
tokenEndpoint: 'https://demo.duendesoftware.com/connect/token',
46+
userInfoEndpoint: 'https://demo.duendesoftware.com/connect/userinfo',
47+
},
48+
hideAccessToken: true,
49+
convertAllRequestsToCorsExceptNavigate: false,
50+
setAccessTokenToNavigateRequests: true,
51+
demonstratingProofOfPossessionNonce: null,
52+
demonstratingProofOfPossessionJwkJson: null,
53+
},
54+
};
5855

59-
it('will return null when url ends with openidWellknownUrlEndWith', () => {
60-
const trustedDomains: TrustedDomains = {
61-
default: [
62-
'https://demo.duendesoftware.com',
63-
'https://kdhttps.auth0.com',
64-
],
65-
};
66-
const url = 'http://url' + openidWellknownUrlEndWith;
67-
expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toBeNull();
68-
});
56+
it('will return null when url ends with openidWellknownUrlEndWith', () => {
57+
const trustedDomains: TrustedDomains = {
58+
default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'],
59+
};
60+
const url = 'http://url' + openidWellknownUrlEndWith;
61+
expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toBeNull();
62+
});
6963

70-
it('will test urls against domains list if accessTokenDomains list is not present', () => {
71-
const trustedDomains: TrustedDomains = {
72-
default: {
73-
domains: ['https://domain'],
74-
showAccessToken: false,
75-
},
76-
};
64+
it('will return null when url is the token endpoint', () => {
65+
const trustedDomains: TrustedDomains = {
66+
default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'],
67+
};
68+
const url = 'https://demo.duendesoftware.com/connect/token';
69+
expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toBeNull();
70+
});
7771

78-
expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toBe(db.default);
79-
});
72+
it('will return null when url is the token endpoint only differs by default port', () => {
73+
const trustedDomains: TrustedDomains = {
74+
default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'],
75+
};
76+
const url = 'https://demo.duendesoftware.com:443/connect/token';
77+
expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toBeNull();
78+
});
8079

81-
it('will test urls against accessTokenDomains list if it is present and ignore domains list', () => {
82-
const trustedDomains: TrustedDomains = {
83-
default: {
84-
domains: ['https://domain'],
85-
accessTokenDomains: ['https://myapi'],
86-
showAccessToken: false,
87-
},
88-
};
80+
it('will return null when url is the token endpoint', () => {
81+
const trustedDomains: TrustedDomains = {
82+
default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'],
83+
};
84+
const url = 'https://demo.duendesoftware.com/connect/revocation';
85+
expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toBeNull();
86+
});
8987

90-
expect(getCurrentDatabaseDomain(db, 'https://myapi/test', trustedDomains)).toBe(db.default);
91-
expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toBeNull();
92-
});
93-
});
88+
it('will not return null when url is the userinfo endpoint', () => {
89+
const trustedDomains: TrustedDomains = {
90+
default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'],
91+
};
92+
const url = 'https://demo.duendesoftware.com/connect/userinfo';
93+
expect(getCurrentDatabaseDomain(db, url, trustedDomains)).not.toBeNull();
94+
});
95+
96+
it('will test urls against domains list if accessTokenDomains list is not present', () => {
97+
const trustedDomains: TrustedDomains = {
98+
default: {
99+
domains: ['https://domain'],
100+
showAccessToken: false,
101+
},
102+
};
103+
104+
expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toBe(db.default);
105+
});
106+
107+
it('will test urls against accessTokenDomains list if it is present and ignore domains list', () => {
108+
const trustedDomains: TrustedDomains = {
109+
default: {
110+
domains: ['https://domain'],
111+
accessTokenDomains: ['https://myapi'],
112+
showAccessToken: false,
113+
},
114+
};
115+
116+
expect(getCurrentDatabaseDomain(db, 'https://myapi/test', trustedDomains)).toBe(db.default);
117+
expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toBeNull();
118+
});
119+
});
120+
it('normalizes urls', () => {
121+
expect(normalizeUrl('foo.com')).toBe('https://foo.com');
122+
expect(normalizeUrl('foo.com ')).toBe('https://foo.com');
123+
expect(normalizeUrl('foo.com.')).toBe('https://foo.com');
124+
expect(normalizeUrl('foo.com')).toBe('https://foo.com');
125+
expect(normalizeUrl('HTTP://foo.com')).toBe('http://foo.com');
126+
expect(normalizeUrl('//foo.com')).toBe('https://foo.com');
127+
expect(normalizeUrl('http://foo.com')).toBe('http://foo.com');
128+
expect(normalizeUrl('http://foo.com:80')).toBe('http://foo.com');
129+
expect(normalizeUrl('https://foo.com:443')).toBe('https://foo.com');
130+
expect(normalizeUrl('http://foo.com/foo/')).toBe('http://foo.com/foo');
131+
expect(normalizeUrl('foo.com/?foo=bar baz')).toBe('https://foo.com/?foo=bar+baz');
132+
expect(normalizeUrl('https://foo.com/https://bar.com')).toBe('https://foo.com/https://bar.com');
133+
expect(normalizeUrl('https://foo.com/https://bar.com/foo//bar')).toBe(
134+
'https://foo.com/https://bar.com/foo/bar',
135+
);
136+
expect(normalizeUrl('https://foo.com/http://bar.com')).toBe('https://foo.com/http://bar.com');
137+
expect(normalizeUrl('https://foo.com/http://bar.com/foo//bar')).toBe(
138+
'https://foo.com/http://bar.com/foo/bar',
139+
);
140+
expect(normalizeUrl('http://foo.com/%7Efoo/')).toBe('http://foo.com/~foo');
141+
expect(normalizeUrl('https://foo.com/%FAIL%/07/94/ca/55.jpg')).toBe(
142+
'https://foo.com/%FAIL%/07/94/ca/55.jpg',
143+
);
144+
expect(normalizeUrl('http://foo.com/?')).toBe('http://foo.com');
145+
expect(normalizeUrl('êxample.com')).toBe('https://xn--xample-hva.com');
146+
expect(normalizeUrl('http://foo.com/?b=bar&a=foo')).toBe('http://foo.com/?a=foo&b=bar');
147+
expect(normalizeUrl('http://foo.com/?foo=bar*|<>:"')).toBe(
148+
'http://foo.com/?foo=bar*|%3C%3E:%22',
149+
);
150+
expect(normalizeUrl('http://foo.com:5000')).toBe('http://foo.com:5000');
151+
expect(normalizeUrl('http://foo.com/foo#bar')).toBe('http://foo.com/foo#bar');
152+
expect(normalizeUrl('http://foo.com/foo/bar/../baz')).toBe('http://foo.com/foo/baz');
153+
expect(normalizeUrl('http://foo.com/foo/bar/./baz')).toBe('http://foo.com/foo/bar/baz');
154+
});
94155
});

0 commit comments

Comments
 (0)