1
- import test from 'ava'
1
+ import anyTest , { TestFn } from 'ava'
2
2
import { CAPABILITIES , makeJWTToken } from '../authorization/jwt.js'
3
- import apiBuilder from './index.js'
3
+ import { spawnTestServer } from '../fixtures/spawnServer.js'
4
+ import { FastifyTypebox } from './index.js'
5
+
6
+ const test = anyTest as TestFn < { server : FastifyTypebox } >
7
+
8
+ test . beforeEach ( async t => {
9
+ t . context . server = await spawnTestServer ( )
10
+ } )
11
+
12
+ test . afterEach . always ( async t => {
13
+ await t . context . server ?. close ( )
14
+ } )
4
15
5
16
test ( 'no auth header should 401' , async t => {
6
- const server = await apiBuilder ( { useMemoryBackedDB : true } )
7
- const responseAdmin = await server . inject ( {
17
+ const responseAdmin = await t . context . server . inject ( {
8
18
method : 'POST' ,
9
19
url : '/v1/admin' ,
10
20
payload : {
11
21
name : 'test_admin'
12
22
}
13
23
} )
14
24
t . is ( responseAdmin . statusCode , 401 , 'returns a status code of 401' )
15
- const responsePublisher = await server . inject ( {
25
+ const responsePublisher = await t . context . server . inject ( {
16
26
method : 'POST' ,
17
27
url : '/v1/publisher' ,
18
28
payload : {
@@ -23,10 +33,9 @@ test('no auth header should 401', async t => {
23
33
} )
24
34
25
35
test ( 'token refresh with non-refresh token should fail' , async t => {
26
- const server = await apiBuilder ( { useMemoryBackedDB : true } )
27
- const tokenAdmin = server . jwt . sign ( makeJWTToken ( { isAdmin : true , isRefresh : false } ) )
28
- const tokenPublisher = server . jwt . sign ( makeJWTToken ( { isAdmin : false , isRefresh : false } ) )
29
- const adminResponse = await server . inject ( {
36
+ const tokenAdmin = t . context . server . jwt . sign ( makeJWTToken ( { isAdmin : true , isRefresh : false } ) )
37
+ const tokenPublisher = t . context . server . jwt . sign ( makeJWTToken ( { isAdmin : false , isRefresh : false } ) )
38
+ const adminResponse = await t . context . server . inject ( {
30
39
method : 'POST' ,
31
40
url : '/v1/auth/exchange' ,
32
41
headers : {
@@ -37,7 +46,7 @@ test('token refresh with non-refresh token should fail', async t => {
37
46
}
38
47
} )
39
48
t . is ( adminResponse . statusCode , 401 , 'refreshing a non-refresh admin token returns a status code of 401' )
40
- const publisherResponse = await server . inject ( {
49
+ const publisherResponse = await t . context . server . inject ( {
41
50
method : 'POST' ,
42
51
url : '/v1/auth/exchange' ,
43
52
headers : {
@@ -51,40 +60,34 @@ test('token refresh with non-refresh token should fail', async t => {
51
60
} )
52
61
53
62
test ( 'revocation works' , async t => {
54
- const server = await apiBuilder ( { useMemoryBackedDB : true } )
55
63
const token = makeJWTToken ( { isAdmin : true , isRefresh : false } )
56
- const signedToken = server . jwt . sign ( token )
64
+ const signedToken = t . context . server . jwt . sign ( token )
57
65
const tokenToBeRevoked = makeJWTToken ( { isAdmin : true , isRefresh : false } )
58
- const signedTokenToBeRevoked = server . jwt . sign ( tokenToBeRevoked )
59
- const revokeResponse = await server . inject ( {
66
+ const signedTokenToBeRevoked = t . context . server . jwt . sign ( tokenToBeRevoked )
67
+ const revokeResponse = await t . context . server . inject ( {
60
68
method : 'DELETE' ,
61
69
url : `/v1/auth/revoke/${ tokenToBeRevoked . tokenId } ` ,
62
70
headers : {
63
71
authorization : `Bearer ${ signedToken } `
64
- } ,
65
- payload : {
66
- capabilities : [ CAPABILITIES . PUBLISHER , CAPABILITIES . REFRESH ]
67
72
}
68
73
} )
69
74
t . is ( revokeResponse . statusCode , 200 , 'revocation of another token works (should return 200)' )
70
75
71
- const failingRevokeResponse = await server . inject ( {
76
+ const failingRevokeResponse = await t . context . server . inject ( {
72
77
method : 'DELETE' ,
73
78
url : `/v1/auth/revoke/${ token . tokenId } ` ,
74
79
headers : {
75
80
authorization : `Bearer ${ signedTokenToBeRevoked } `
76
- } ,
77
- payload : {
78
- capabilities : [ CAPABILITIES . PUBLISHER , CAPABILITIES . REFRESH ]
79
81
}
80
82
} )
81
83
t . is ( failingRevokeResponse . statusCode , 401 , 'trying to revoke the original token using the revoked token should no longer work' )
82
84
} )
83
85
84
- test ( 'requesting new token with superset of permissions (publisher -> admin) should fail' , async t => {
85
- const server = await apiBuilder ( { useMemoryBackedDB : true } )
86
- const token = server . jwt . sign ( makeJWTToken ( { isAdmin : false , isRefresh : true } ) )
87
- const response = await server . inject ( {
86
+ test ( 'revoking a tokens removes all tokens derived from that token' , async t => {
87
+ // first token
88
+ const tokenBody = makeJWTToken ( { isAdmin : true , isRefresh : true } )
89
+ const token = t . context . server . jwt . sign ( tokenBody )
90
+ const response = await t . context . server . inject ( {
88
91
method : 'POST' ,
89
92
url : '/v1/auth/exchange' ,
90
93
headers : {
@@ -94,29 +97,49 @@ test('requesting new token with superset of permissions (publisher -> admin) sho
94
97
capabilities : [ CAPABILITIES . ADMIN , CAPABILITIES . PUBLISHER , CAPABILITIES . REFRESH ]
95
98
}
96
99
} )
97
- t . is ( response . statusCode , 401 )
100
+ t . is ( response . statusCode , 200 , 'publisher refreshing their own token works' )
101
+
102
+ const refreshedToken = response . body
103
+ const revokeResponse = await t . context . server . inject ( {
104
+ method : 'DELETE' ,
105
+ url : `/v1/auth/revoke/${ tokenBody . tokenId } ` ,
106
+ headers : {
107
+ authorization : `Bearer ${ refreshedToken } `
108
+ }
109
+ } )
110
+ t . is ( revokeResponse . statusCode , 200 , 'revoking original token should work' )
111
+
112
+ const newPublisherResponse = await t . context . server . inject ( {
113
+ method : 'POST' ,
114
+ url : '/v1/publisher' ,
115
+ headers : {
116
+ authorization : `Bearer ${ refreshedToken } `
117
+ } ,
118
+ payload : {
119
+ name : 'malicious new publisher'
120
+ }
121
+ } )
122
+ t . is ( newPublisherResponse . statusCode , 401 , 'operations with token derived from original token should also fail' )
98
123
} )
99
124
100
- test ( 'requesting new token with subset of permissions (admin -> publisher) should work' , async t => {
101
- const server = await apiBuilder ( { useMemoryBackedDB : true } )
102
- const token = server . jwt . sign ( makeJWTToken ( { isAdmin : true , isRefresh : true } ) )
103
- const response = await server . inject ( {
125
+ test ( 'requesting new token with superset of permissions (publisher -> admin) should fail' , async t => {
126
+ const token = t . context . server . jwt . sign ( makeJWTToken ( { isAdmin : false , isRefresh : true } ) )
127
+ const response = await t . context . server . inject ( {
104
128
method : 'POST' ,
105
129
url : '/v1/auth/exchange' ,
106
130
headers : {
107
131
authorization : `Bearer ${ token } `
108
132
} ,
109
133
payload : {
110
- capabilities : [ CAPABILITIES . PUBLISHER , CAPABILITIES . REFRESH ]
134
+ capabilities : [ CAPABILITIES . ADMIN , CAPABILITIES . PUBLISHER , CAPABILITIES . REFRESH ]
111
135
}
112
136
} )
113
- t . is ( response . statusCode , 200 )
137
+ t . is ( response . statusCode , 401 )
114
138
} )
115
139
116
- test ( 'trying to create new refresh tokens as a publisher should fail' , async t => {
117
- const server = await apiBuilder ( { useMemoryBackedDB : true } )
118
- const token = server . jwt . sign ( makeJWTToken ( { isAdmin : false , isRefresh : true } ) )
119
- const response = await server . inject ( {
140
+ test ( 'requesting new token with subset of permissions (admin -> publisher) should work' , async t => {
141
+ const token = t . context . server . jwt . sign ( makeJWTToken ( { isAdmin : true , isRefresh : true } ) )
142
+ const response = await t . context . server . inject ( {
120
143
method : 'POST' ,
121
144
url : '/v1/auth/exchange' ,
122
145
headers : {
@@ -126,5 +149,5 @@ test('trying to create new refresh tokens as a publisher should fail', async t =
126
149
capabilities : [ CAPABILITIES . PUBLISHER , CAPABILITIES . REFRESH ]
127
150
}
128
151
} )
129
- t . is ( response . statusCode , 401 )
152
+ t . is ( response . statusCode , 200 )
130
153
} )
0 commit comments