Skip to content

Commit 4697887

Browse files
authored
Merge pull request #72 from craftship/add-logout
CLI: Logout
2 parents a22e89b + 3846385 commit 4697887

File tree

4 files changed

+192
-0
lines changed

4 files changed

+192
-0
lines changed

serverless.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ functions:
9494
path: 'registry/-/user/{id}'
9595
method: put
9696

97+
userDelete:
98+
handler: userDelete.default
99+
events:
100+
- http:
101+
path: 'registry/-/user/token/{token}'
102+
method: delete
103+
authorizer: authorizerGithub
104+
97105
tarGet:
98106
handler: tarGet.default
99107
events:

src/user/delete.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import url from 'url';
2+
import GitHub from 'github';
3+
4+
export default async ({ pathParameters }, context, callback) => {
5+
const {
6+
token,
7+
} = pathParameters;
8+
9+
const parsedUrl = url.parse(process.env.githubUrl);
10+
const github = new GitHub({
11+
host: parsedUrl.host,
12+
protocol: 'https',
13+
pathPrefix: parsedUrl.path,
14+
});
15+
16+
github.authenticate({
17+
type: 'basic',
18+
username: process.env.githubClientId,
19+
password: process.env.githubSecret,
20+
});
21+
22+
try {
23+
await github.authorization.reset({
24+
client_id: process.env.githubClientId,
25+
access_token: token,
26+
});
27+
28+
return callback(null, {
29+
statusCode: 200,
30+
body: JSON.stringify({
31+
ok: true,
32+
}),
33+
});
34+
} catch (err) {
35+
return callback(null, {
36+
statusCode: 500,
37+
body: JSON.stringify({
38+
ok: false,
39+
error: err.message,
40+
}),
41+
});
42+
}
43+
};

test/user/delete.test.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/* eslint-disable no-underscore-dangle */
2+
import GitHub from 'github';
3+
import subject from '../../src/user/delete';
4+
5+
describe('DELETE /registry/-/user/token/{token}', () => {
6+
let event;
7+
let callback;
8+
let gitHubSpy;
9+
let gitHubInstance;
10+
11+
beforeEach(() => {
12+
const env = {
13+
githubClientId: 'foo-client-id',
14+
githubSecret: 'bar-secret',
15+
githubUrl: 'https://example.com',
16+
restrictedOrgs: 'foo-org',
17+
};
18+
19+
process.env = env;
20+
21+
callback = stub();
22+
});
23+
24+
describe('logout', () => {
25+
context('with valid token', () => {
26+
let authStub;
27+
let resetAuthStub;
28+
29+
beforeEach(() => {
30+
event = {
31+
pathParameters: {
32+
token: 'foo-token',
33+
},
34+
};
35+
36+
gitHubSpy = spy(() => {
37+
gitHubInstance = createStubInstance(GitHub);
38+
authStub = stub();
39+
resetAuthStub = stub();
40+
41+
gitHubInstance.authenticate = authStub;
42+
gitHubInstance.authorization = {
43+
reset: resetAuthStub,
44+
};
45+
46+
return gitHubInstance;
47+
});
48+
49+
subject.__Rewire__({
50+
GitHub: gitHubSpy,
51+
});
52+
});
53+
54+
it('should authenticate using app credentials with github', async () => {
55+
await subject(event, stub(), callback);
56+
57+
assert(authStub.calledWithExactly({
58+
type: 'basic',
59+
username: 'foo-client-id',
60+
password: 'bar-secret',
61+
}));
62+
});
63+
64+
it('should reset token with github', async () => {
65+
await subject(event, stub(), callback);
66+
67+
assert(resetAuthStub.calledWithExactly({
68+
client_id: 'foo-client-id',
69+
access_token: 'foo-token',
70+
}));
71+
});
72+
73+
it('should return 200 response', async () => {
74+
await subject(event, stub(), callback);
75+
76+
assert(callback.calledWithExactly(null, {
77+
statusCode: 200,
78+
body: '{"ok":true}',
79+
}));
80+
});
81+
82+
afterEach(() => {
83+
subject.__ResetDependency__('GitHub');
84+
});
85+
});
86+
87+
context('with invalid token', () => {
88+
let authStub;
89+
let resetAuthStub;
90+
91+
beforeEach(() => {
92+
event = {
93+
pathParameters: {
94+
token: 'foo-bad-token',
95+
},
96+
};
97+
98+
gitHubSpy = spy(() => {
99+
gitHubInstance = createStubInstance(GitHub);
100+
authStub = stub();
101+
resetAuthStub = stub().throws(new Error('Invalid token'));
102+
103+
gitHubInstance.authenticate = authStub;
104+
gitHubInstance.authorization = {
105+
reset: resetAuthStub,
106+
};
107+
108+
return gitHubInstance;
109+
});
110+
111+
subject.__Rewire__({
112+
GitHub: gitHubSpy,
113+
});
114+
});
115+
116+
it('should authenticate using app credentials with github', async () => {
117+
await subject(event, stub(), callback);
118+
119+
assert(authStub.calledWithExactly({
120+
type: 'basic',
121+
username: 'foo-client-id',
122+
password: 'bar-secret',
123+
}));
124+
});
125+
126+
it('should return a 500 error', async () => {
127+
await subject(event, stub(), callback);
128+
129+
assert(callback.calledWithExactly(null, {
130+
statusCode: 500,
131+
body: '{"ok":false,"error":"Invalid token"}',
132+
}));
133+
});
134+
135+
afterEach(() => {
136+
subject.__ResetDependency__('GitHub');
137+
});
138+
});
139+
});
140+
});

webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module.exports = {
1212
distTagsPut: ['./bootstrap', './src/dist-tags/put.js'],
1313
distTagsDelete: ['./bootstrap', './src/dist-tags/delete.js'],
1414
userPut: ['./bootstrap', './src/user/put.js'],
15+
userDelete: ['./bootstrap', './src/user/delete.js'],
1516
tarGet: ['./bootstrap', './src/tar/get.js'],
1617
},
1718
output: {

0 commit comments

Comments
 (0)