forked from TeamCodeStream/codestream-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathslack_auth.js
More file actions
175 lines (155 loc) · 4.56 KB
/
Copy pathslack_auth.js
File metadata and controls
175 lines (155 loc) · 4.56 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// provide service to handle slack credential authorization
'use strict';
const Fetch = require('node-fetch');
const OAuthModule = require(process.env.CSSVC_BACKEND_ROOT + '/api_server/lib/oauth/oauth_module.js');
const SlackAuthorizer = require('./slack_authorizer');
const USER_SCOPES = [
'channels:read',
'channels:write',
'chat:write',
'groups:read',
'groups:write',
'im:read',
'mpim:read',
'mpim:write',
'users.profile:write',
'users:read',
'users:read.email'
];
const BOT_SCOPES = [
'channels:history',
'channels:read',
'chat:write',
'groups:history',
'groups:read',
'mpim:history',
'mpim:read',
'users:read',
'users:read.email'
];
const OAUTH_CONFIG = {
provider: 'slack',
host: 'slack.com',
apiHost: 'slack.com/api',
authPath: 'oauth/v2/authorize',
tokenPath: 'api/oauth.v2.access',
exchangeFormat: 'form',
scopes: USER_SCOPES.join(' '),
hasSharing: true,
scopeParameter: 'user_scope',
hasServerToken: true,
botScopeParameter: 'scope',
botScopes: BOT_SCOPES.join(' ')
};
class SlackAuth extends OAuthModule {
constructor (config) {
super(config);
this.oauthConfig = OAUTH_CONFIG;
}
async authorizeProviderInfo (providerInfo, options) {
return await new SlackAuthorizer({
providerInfo,
options
}).exchangeAndAuthorize();
}
getRedirectData (options) {
const { url, parameters } = super.getRedirectData(options);
if (options.requestServerToken) {
const { botScopes, botScopeParameter } = this.oauthConfig;
parameters[botScopeParameter] = botScopes;
}
return { url, parameters };
}
// overrides OAuthModule.getClientInfo to use "sharing model" app
getClientInfo(options) {
const info = super.getClientInfo(options);
info.clientId = this.apiConfig.appClientId;
info.clientSecret = this.apiConfig.appClientSecret;
return info;
}
// overrides OAuthModule.normalizeTokenDataResponse, to get the buried access token and other info
// since Slack updated their OAuth API to v2, we're trying to make this look like the data we got back from V1,
// so we don't have to do a client update ... see https://api.slack.com/authentication/migration
normalizeTokenDataResponse (responseData) {
let serverToken;
if (responseData.access_token) {
serverToken = {
access_token: responseData.access_token,
scope: responseData.scope
};
}
responseData.access_token = (responseData.authed_user || {}).access_token;
responseData.user_id = (responseData.authed_user || {}).id;
responseData.team_id = (responseData.team || {}).id;
responseData.team_name = (responseData.team || {}).name;
responseData.scope = (responseData.authed_user || {}).scope;
if (serverToken) {
serverToken = {
...responseData,
...serverToken
};
delete serverToken.user_id;
delete serverToken.authed_user;
delete responseData.bot_user_id;
delete responseData.token_type;
const userToken = super.normalizeTokenDataResponse(responseData);
serverToken = super.normalizeTokenDataResponse(serverToken);
return { userToken, serverToken };
}
return super.normalizeTokenDataResponse(responseData);
}
validateChannelName (name) {
if (name.match(/[^a-z0-9-_[\]{}\\/]/)) {
return 'illegal characters in channel name';
}
if (name.length > 21) {
return 'name must be no longer than 21 characters';
}
}
// match the given slack identity to a CodeStream identity
async getUserIdentity (options) {
const authorizer = new SlackAuthorizer({ options });
return await authorizer.getSlackIdentity(
options.accessToken,
options.providerInfo
);
}
async getServerTokenMultiAuthKey (info) {
return info.data.team_id;
}
// an access token can be maintained for each slack workspace
async getMultiAuthExtraData (info, options) {
const data = {};
try {
const request = await Fetch(
`https://slack.com/api/users.info?user=${info.data.user_id}&include_locale=true`,
{
method: 'get',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${info.accessToken}`
}
}
);
const response = await request.json();
if (!response.ok) {
options.request.warn('Error obtaining slack user info', response.error);
throw options.request.errorHandler.error('providerDataRequestFailed');
}
data[info.data.team_id] = {
locale: response.user.locale,
tz: response.user.tz,
tz_label: response.user.tz_label
};
}
catch (error) {
options.request.warn('Request to Slack API failed: ' + error.message);
throw error;
}
return data;
}
async getUserId(info) {
return info && info.data ? info.data.user_id : undefined;
}
}
module.exports = SlackAuth;