@adonisjs/ally 5.0.0-6 → 5.0.0-8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -8
- package/build/chunk-CSAU5B4Q.js +10 -0
- package/build/chunk-CSAU5B4Q.js.map +1 -0
- package/build/chunk-OSVNBZ7V.js +164 -0
- package/build/chunk-OSVNBZ7V.js.map +1 -0
- package/build/chunk-UF7PETXM.js +83 -0
- package/build/chunk-UF7PETXM.js.map +1 -0
- package/build/chunk-UIZWPBWM.js +38 -0
- package/build/chunk-UIZWPBWM.js.map +1 -0
- package/build/chunk-Y3GA4Y2H.js +170 -0
- package/build/chunk-Y3GA4Y2H.js.map +1 -0
- package/build/discord-NGJGLGX7.js +136 -0
- package/build/discord-NGJGLGX7.js.map +1 -0
- package/build/facebook-WTZGLDH5.js +137 -0
- package/build/facebook-WTZGLDH5.js.map +1 -0
- package/build/github-24BPMULZ.js +173 -0
- package/build/github-24BPMULZ.js.map +1 -0
- package/build/google-NMLTQESR.js +184 -0
- package/build/google-NMLTQESR.js.map +1 -0
- package/build/index.d.ts +0 -1
- package/build/index.js +151 -17
- package/build/index.js.map +1 -0
- package/build/linked_in-HIRSEAEP.js +153 -0
- package/build/linked_in-HIRSEAEP.js.map +1 -0
- package/build/providers/ally_provider.js +33 -36
- package/build/providers/ally_provider.js.map +1 -0
- package/build/spotify-ESJDFUD6.js +118 -0
- package/build/spotify-ESJDFUD6.js.map +1 -0
- package/build/twitter-QISDDK24.js +101 -0
- package/build/twitter-QISDDK24.js.map +1 -0
- package/package.json +45 -33
- package/build/configure.js +0 -48
- package/build/src/abstract_drivers/oauth1.js +0 -188
- package/build/src/abstract_drivers/oauth2.js +0 -175
- package/build/src/ally_manager.js +0 -40
- package/build/src/debug.js +0 -10
- package/build/src/define_config.js +0 -75
- package/build/src/drivers/discord.js +0 -156
- package/build/src/drivers/facebook.js +0 -155
- package/build/src/drivers/github.js +0 -213
- package/build/src/drivers/google.js +0 -197
- package/build/src/drivers/linked_in.js +0 -166
- package/build/src/drivers/spotify.js +0 -130
- package/build/src/drivers/twitter.js +0 -117
- package/build/src/errors.js +0 -11
- package/build/src/redirect_request.js +0 -63
- package/build/src/types.js +0 -9
- package/build/stubs/main.js +0 -10
- /package/build/{stubs/config.stub → config/ally.stub} +0 -0
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @adonisjs/ally
|
|
3
|
-
*
|
|
4
|
-
* (c) AdonisJS
|
|
5
|
-
*
|
|
6
|
-
* For the full copyright and license information, please view the LICENSE
|
|
7
|
-
* file that was distributed with this source code.
|
|
8
|
-
*/
|
|
9
|
-
import { Oauth2Driver } from '../abstract_drivers/oauth2.js';
|
|
10
|
-
/**
|
|
11
|
-
* Github driver to login user via Github
|
|
12
|
-
*/
|
|
13
|
-
export class GithubDriver extends Oauth2Driver {
|
|
14
|
-
config;
|
|
15
|
-
accessTokenUrl = 'https://github.com/login/oauth/access_token';
|
|
16
|
-
authorizeUrl = 'https://github.com/login/oauth/authorize';
|
|
17
|
-
userInfoUrl = 'https://api.github.com/user';
|
|
18
|
-
userEmailUrl = 'https://api.github.com/user/emails';
|
|
19
|
-
/**
|
|
20
|
-
* The param name for the authorization code
|
|
21
|
-
*/
|
|
22
|
-
codeParamName = 'code';
|
|
23
|
-
/**
|
|
24
|
-
* The param name for the error
|
|
25
|
-
*/
|
|
26
|
-
errorParamName = 'error';
|
|
27
|
-
/**
|
|
28
|
-
* Cookie name for storing the "gh_oauth_state"
|
|
29
|
-
*/
|
|
30
|
-
stateCookieName = 'gh_oauth_state';
|
|
31
|
-
/**
|
|
32
|
-
* Parameter name to be used for sending and receiving the state
|
|
33
|
-
* from Github
|
|
34
|
-
*/
|
|
35
|
-
stateParamName = 'state';
|
|
36
|
-
/**
|
|
37
|
-
* Parameter name for defining the scopes
|
|
38
|
-
*/
|
|
39
|
-
scopeParamName = 'scope';
|
|
40
|
-
/**
|
|
41
|
-
* Scopes separator
|
|
42
|
-
*/
|
|
43
|
-
scopesSeparator = ' ';
|
|
44
|
-
constructor(ctx, config) {
|
|
45
|
-
super(ctx, config);
|
|
46
|
-
this.config = config;
|
|
47
|
-
/**
|
|
48
|
-
* Extremely important to call the following method to clear the
|
|
49
|
-
* state set by the redirect request
|
|
50
|
-
*/
|
|
51
|
-
this.loadState();
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Configuring the redirect request with defaults
|
|
55
|
-
*/
|
|
56
|
-
configureRedirectRequest(request) {
|
|
57
|
-
/**
|
|
58
|
-
* Define user defined scopes or the default one's
|
|
59
|
-
*/
|
|
60
|
-
request.scopes(this.config.scopes || ['user']);
|
|
61
|
-
/**
|
|
62
|
-
* Set "allow_signup" option when defined
|
|
63
|
-
*/
|
|
64
|
-
if (this.config.allowSignup !== undefined) {
|
|
65
|
-
request.param('allow_signup', this.config.allowSignup);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Set "login" option when defined
|
|
69
|
-
*/
|
|
70
|
-
if (this.config.login) {
|
|
71
|
-
request.param('login', this.config.login);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Configuring the access token API request to send extra fields
|
|
76
|
-
*/
|
|
77
|
-
configureAccessTokenRequest(request) {
|
|
78
|
-
/**
|
|
79
|
-
* Send state to github when request is not stateles
|
|
80
|
-
*/
|
|
81
|
-
if (!this.isStateless) {
|
|
82
|
-
request.field('state', this.stateCookieValue);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Clearing the default defined "grant_type". Github doesn't accept this.
|
|
86
|
-
* https://github.com/poppinss/oauth-client#following-is-the-list-of-fieldsparams-set-by-the-clients-implicitly
|
|
87
|
-
*/
|
|
88
|
-
request.clearField('grant_type');
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Returns the HTTP request with the authorization header set
|
|
92
|
-
*/
|
|
93
|
-
getAuthenticatedRequest(url, token) {
|
|
94
|
-
const request = this.httpClient(url);
|
|
95
|
-
request.header('Authorization', `token ${token}`);
|
|
96
|
-
request.header('Accept', 'application/json');
|
|
97
|
-
request.parseAs('json');
|
|
98
|
-
return request;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Fetches the user info from the Github API
|
|
102
|
-
* https://docs.github.com/en/rest/reference/users#get-the-authenticated-user
|
|
103
|
-
*/
|
|
104
|
-
async getUserInfo(token, callback) {
|
|
105
|
-
const request = this.getAuthenticatedRequest(this.config.userInfoUrl || this.userInfoUrl, token);
|
|
106
|
-
if (typeof callback === 'function') {
|
|
107
|
-
callback(request);
|
|
108
|
-
}
|
|
109
|
-
const body = await request.get();
|
|
110
|
-
return {
|
|
111
|
-
id: body.id,
|
|
112
|
-
nickName: body.name,
|
|
113
|
-
email: body.email,
|
|
114
|
-
emailVerificationState: (body.email
|
|
115
|
-
? 'verified'
|
|
116
|
-
: 'unsupported'),
|
|
117
|
-
name: body.name,
|
|
118
|
-
avatarUrl: body.avatar_url,
|
|
119
|
-
original: body,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Fetches the user email from the Github API.
|
|
124
|
-
* https://docs.github.com/en/rest/reference/users#list-email-addresses-for-the-authenticated-user
|
|
125
|
-
*/
|
|
126
|
-
async getUserEmail(token, callback) {
|
|
127
|
-
const request = this.getAuthenticatedRequest(this.config.userEmailUrl || this.userEmailUrl, token);
|
|
128
|
-
if (typeof callback === 'function') {
|
|
129
|
-
callback(request);
|
|
130
|
-
}
|
|
131
|
-
try {
|
|
132
|
-
let emails = await request.get();
|
|
133
|
-
/**
|
|
134
|
-
* Sort emails to keep the primary ones on the top
|
|
135
|
-
*/
|
|
136
|
-
emails = emails.sort((email) => (email.primary ? -1 : 1));
|
|
137
|
-
/**
|
|
138
|
-
* Get the first verified email of the user
|
|
139
|
-
*/
|
|
140
|
-
let mainEmail = emails.find((email) => email.verified);
|
|
141
|
-
/**
|
|
142
|
-
* If there are no verified emails, then get any first one
|
|
143
|
-
*/
|
|
144
|
-
if (!mainEmail) {
|
|
145
|
-
mainEmail = emails[0];
|
|
146
|
-
}
|
|
147
|
-
return mainEmail;
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
if (error && error.response && error.response.statusCode === 404) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
throw error;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Find if the current error code is for access denied
|
|
158
|
-
*/
|
|
159
|
-
accessDenied() {
|
|
160
|
-
const error = this.getError();
|
|
161
|
-
if (!error) {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
return error === 'access_denied';
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Returns details for the authorized user
|
|
168
|
-
*/
|
|
169
|
-
async user(callback) {
|
|
170
|
-
const token = await this.accessToken(callback);
|
|
171
|
-
const user = await this.getUserInfo(token.token, callback);
|
|
172
|
-
/**
|
|
173
|
-
* Fetch email separately
|
|
174
|
-
*/
|
|
175
|
-
if (!user.email) {
|
|
176
|
-
this.ctx.logger.trace('Fetching github user email separately');
|
|
177
|
-
const emailResponse = await this.getUserEmail(token.token, callback);
|
|
178
|
-
if (emailResponse) {
|
|
179
|
-
user.email = emailResponse.email;
|
|
180
|
-
user.emailVerificationState = emailResponse.verified
|
|
181
|
-
? 'verified'
|
|
182
|
-
: 'unverified';
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
...user,
|
|
187
|
-
token: token,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Finds the user by the access token
|
|
192
|
-
*/
|
|
193
|
-
async userFromToken(token, callback) {
|
|
194
|
-
const user = await this.getUserInfo(token, callback);
|
|
195
|
-
/**
|
|
196
|
-
* Fetch email separately
|
|
197
|
-
*/
|
|
198
|
-
if (!user.email) {
|
|
199
|
-
this.ctx.logger.trace('Fetching github user email separately');
|
|
200
|
-
const emailResponse = await this.getUserEmail(token, callback);
|
|
201
|
-
if (emailResponse) {
|
|
202
|
-
user.email = emailResponse.email;
|
|
203
|
-
user.emailVerificationState = emailResponse.verified
|
|
204
|
-
? 'verified'
|
|
205
|
-
: 'unverified';
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return {
|
|
209
|
-
...user,
|
|
210
|
-
token: { token, type: 'bearer' },
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @adonisjs/ally
|
|
3
|
-
*
|
|
4
|
-
* (c) AdonisJS
|
|
5
|
-
*
|
|
6
|
-
* For the full copyright and license information, please view the LICENSE
|
|
7
|
-
* file that was distributed with this source code.
|
|
8
|
-
*/
|
|
9
|
-
import { Oauth2Driver } from '../abstract_drivers/oauth2.js';
|
|
10
|
-
const SCOPE_PREFIXES = {
|
|
11
|
-
'https://www.googleapis.com/auth': [
|
|
12
|
-
'userinfo.email',
|
|
13
|
-
'userinfo.profile',
|
|
14
|
-
'contacts',
|
|
15
|
-
'contacts.other.readonly',
|
|
16
|
-
'contacts.readonly',
|
|
17
|
-
'directory.readonly',
|
|
18
|
-
'user.addresses.read',
|
|
19
|
-
'user.birthday.read',
|
|
20
|
-
'user.emails.read',
|
|
21
|
-
'user.gender.read',
|
|
22
|
-
'user.organization.read',
|
|
23
|
-
'user.phonenumbers.read',
|
|
24
|
-
'analytics',
|
|
25
|
-
'analytics.readonly',
|
|
26
|
-
'documents',
|
|
27
|
-
'documents.readonly',
|
|
28
|
-
'forms',
|
|
29
|
-
'forms.currentonly',
|
|
30
|
-
'groups',
|
|
31
|
-
'spreadsheets',
|
|
32
|
-
'calendar',
|
|
33
|
-
'calendar.events',
|
|
34
|
-
'calendar.events.readonly',
|
|
35
|
-
'calendar.readonly',
|
|
36
|
-
'calendar.settings.readonly',
|
|
37
|
-
'drive',
|
|
38
|
-
'drive.appdata',
|
|
39
|
-
'drive.file',
|
|
40
|
-
'drive.metadata',
|
|
41
|
-
'drive.metadata.readonly',
|
|
42
|
-
'drive.photos.readonly',
|
|
43
|
-
'drive.readonly',
|
|
44
|
-
'drive.scripts',
|
|
45
|
-
],
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Google driver to login user via Google
|
|
49
|
-
*/
|
|
50
|
-
export class GoogleDriver extends Oauth2Driver {
|
|
51
|
-
config;
|
|
52
|
-
accessTokenUrl = 'https://oauth2.googleapis.com/token';
|
|
53
|
-
authorizeUrl = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
54
|
-
userInfoUrl = 'https://www.googleapis.com/oauth2/v3/userinfo';
|
|
55
|
-
/**
|
|
56
|
-
* The param name for the authorization code
|
|
57
|
-
*/
|
|
58
|
-
codeParamName = 'code';
|
|
59
|
-
/**
|
|
60
|
-
* The param name for the error
|
|
61
|
-
*/
|
|
62
|
-
errorParamName = 'error';
|
|
63
|
-
/**
|
|
64
|
-
* Cookie name for storing the "google_oauth_state"
|
|
65
|
-
*/
|
|
66
|
-
stateCookieName = 'google_oauth_state';
|
|
67
|
-
/**
|
|
68
|
-
* Parameter name to be used for sending and receiving the state
|
|
69
|
-
* from google
|
|
70
|
-
*/
|
|
71
|
-
stateParamName = 'state';
|
|
72
|
-
/**
|
|
73
|
-
* Parameter name for defining the scopes
|
|
74
|
-
*/
|
|
75
|
-
scopeParamName = 'scope';
|
|
76
|
-
/**
|
|
77
|
-
* Scopes separator
|
|
78
|
-
*/
|
|
79
|
-
scopesSeparator = ' ';
|
|
80
|
-
constructor(ctx, config) {
|
|
81
|
-
super(ctx, config);
|
|
82
|
-
this.config = config;
|
|
83
|
-
/**
|
|
84
|
-
* Extremely important to call the following method to clear the
|
|
85
|
-
* state set by the redirect request
|
|
86
|
-
*/
|
|
87
|
-
this.loadState();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Configuring the redirect request with defaults
|
|
91
|
-
*/
|
|
92
|
-
configureRedirectRequest(request) {
|
|
93
|
-
request.transformScopes((scopes) => this.buildScopes(scopes));
|
|
94
|
-
/**
|
|
95
|
-
* Define user defined scopes or the default one's
|
|
96
|
-
*/
|
|
97
|
-
request.scopes(this.config.scopes || ['openid', 'userinfo.email', 'userinfo.profile']);
|
|
98
|
-
/**
|
|
99
|
-
* Set "response_type" param
|
|
100
|
-
*/
|
|
101
|
-
request.param('response_type', 'code');
|
|
102
|
-
/**
|
|
103
|
-
* Define params based upon user config
|
|
104
|
-
*/
|
|
105
|
-
if (this.config.accessType) {
|
|
106
|
-
request.param('access_type', this.config.accessType);
|
|
107
|
-
}
|
|
108
|
-
if (this.config.prompt) {
|
|
109
|
-
request.param('prompt', this.config.prompt);
|
|
110
|
-
}
|
|
111
|
-
if (this.config.display) {
|
|
112
|
-
request.param('display', this.config.display);
|
|
113
|
-
}
|
|
114
|
-
if (this.config.hostedDomain) {
|
|
115
|
-
request.param('hd', this.config.hostedDomain);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Returns the HTTP request with the authorization header set
|
|
120
|
-
*/
|
|
121
|
-
getAuthenticatedRequest(url, token) {
|
|
122
|
-
const request = this.httpClient(url);
|
|
123
|
-
request.header('Authorization', `Bearer ${token}`);
|
|
124
|
-
request.header('Accept', 'application/json');
|
|
125
|
-
request.parseAs('json');
|
|
126
|
-
return request;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Fetches the user info from the Google API
|
|
130
|
-
*/
|
|
131
|
-
async getUserInfo(token, callback) {
|
|
132
|
-
const request = this.getAuthenticatedRequest(this.config.userInfoUrl || this.userInfoUrl, token);
|
|
133
|
-
if (typeof callback === 'function') {
|
|
134
|
-
callback(request);
|
|
135
|
-
}
|
|
136
|
-
const body = await request.get();
|
|
137
|
-
return {
|
|
138
|
-
id: body.sub,
|
|
139
|
-
nickName: body.name,
|
|
140
|
-
name: body.name,
|
|
141
|
-
email: body.email,
|
|
142
|
-
avatarUrl: body.picture,
|
|
143
|
-
emailVerificationState: body.email_verified ? 'verified' : 'unverified',
|
|
144
|
-
original: body,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Find if the current error code is for access denied
|
|
149
|
-
*/
|
|
150
|
-
accessDenied() {
|
|
151
|
-
const error = this.getError();
|
|
152
|
-
if (!error) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
return error === 'access_denied';
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Get access token
|
|
159
|
-
*/
|
|
160
|
-
async accessToken(callback) {
|
|
161
|
-
const token = await super.accessToken(callback);
|
|
162
|
-
return {
|
|
163
|
-
...token,
|
|
164
|
-
idToken: token.id_token,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Returns details for the authorized user
|
|
169
|
-
*/
|
|
170
|
-
async user(callback) {
|
|
171
|
-
const token = await this.accessToken(callback);
|
|
172
|
-
const user = await this.getUserInfo(token.token, callback);
|
|
173
|
-
return {
|
|
174
|
-
...user,
|
|
175
|
-
token: token,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Finds the user by the access token
|
|
180
|
-
*/
|
|
181
|
-
async userFromToken(token, callback) {
|
|
182
|
-
const user = await this.getUserInfo(token, callback);
|
|
183
|
-
return {
|
|
184
|
-
...user,
|
|
185
|
-
token: { token, type: 'bearer' },
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Prefixes google scopes with the url
|
|
190
|
-
*/
|
|
191
|
-
buildScopes(scopes) {
|
|
192
|
-
return scopes.map((name) => {
|
|
193
|
-
const prefix = Object.keys(SCOPE_PREFIXES).find((one) => SCOPE_PREFIXES[one].includes(name));
|
|
194
|
-
return prefix ? `${prefix}/${name}` : name;
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @adonisjs/ally
|
|
3
|
-
*
|
|
4
|
-
* (c) AdonisJS
|
|
5
|
-
*
|
|
6
|
-
* For the full copyright and license information, please view the LICENSE
|
|
7
|
-
* file that was distributed with this source code.
|
|
8
|
-
*/
|
|
9
|
-
import { Exception } from '@poppinss/utils';
|
|
10
|
-
import { Oauth2Driver } from '../abstract_drivers/oauth2.js';
|
|
11
|
-
/**
|
|
12
|
-
* LinkedIn driver to login user via LinkedIn
|
|
13
|
-
*/
|
|
14
|
-
export class LinkedInDriver extends Oauth2Driver {
|
|
15
|
-
config;
|
|
16
|
-
accessTokenUrl = 'https://www.linkedin.com/oauth/v2/accessToken';
|
|
17
|
-
authorizeUrl = 'https://www.linkedin.com/oauth/v2/authorization';
|
|
18
|
-
userInfoUrl = 'https://api.linkedin.com/v2/me';
|
|
19
|
-
userEmailUrl = 'https://api.linkedin.com/v2/clientAwareMemberHandles';
|
|
20
|
-
/**
|
|
21
|
-
* The param name for the authorization code
|
|
22
|
-
*/
|
|
23
|
-
codeParamName = 'code';
|
|
24
|
-
/**
|
|
25
|
-
* The param name for the error
|
|
26
|
-
*/
|
|
27
|
-
errorParamName = 'error';
|
|
28
|
-
/**
|
|
29
|
-
* Cookie name for storing the "linkedin_oauth_state"
|
|
30
|
-
*/
|
|
31
|
-
stateCookieName = 'linkedin_oauth_state';
|
|
32
|
-
/**
|
|
33
|
-
* Parameter name to be used for sending and receiving the state
|
|
34
|
-
* from linkedin
|
|
35
|
-
*/
|
|
36
|
-
stateParamName = 'state';
|
|
37
|
-
/**
|
|
38
|
-
* Parameter name for defining the scopes
|
|
39
|
-
*/
|
|
40
|
-
scopeParamName = 'scope';
|
|
41
|
-
/**
|
|
42
|
-
* Scopes separator
|
|
43
|
-
*/
|
|
44
|
-
scopesSeparator = ' ';
|
|
45
|
-
constructor(ctx, config) {
|
|
46
|
-
super(ctx, config);
|
|
47
|
-
this.config = config;
|
|
48
|
-
/**
|
|
49
|
-
* Extremely important to call the following method to clear the
|
|
50
|
-
* state set by the redirect request
|
|
51
|
-
*/
|
|
52
|
-
this.loadState();
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Configuring the redirect request with defaults
|
|
56
|
-
*/
|
|
57
|
-
configureRedirectRequest(request) {
|
|
58
|
-
/**
|
|
59
|
-
* Define user defined scopes or the default one's
|
|
60
|
-
*/
|
|
61
|
-
request.scopes(this.config.scopes || ['r_emailaddress', 'r_liteprofile']);
|
|
62
|
-
/**
|
|
63
|
-
* Set "response_type" param
|
|
64
|
-
*/
|
|
65
|
-
request.param('response_type', 'code');
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Returns the HTTP request with the authorization header set
|
|
69
|
-
*/
|
|
70
|
-
getAuthenticatedRequest(url, token) {
|
|
71
|
-
const request = this.httpClient(url);
|
|
72
|
-
request.header('Authorization', `Bearer ${token}`);
|
|
73
|
-
request.header('Accept', 'application/json');
|
|
74
|
-
request.parseAs('json');
|
|
75
|
-
return request;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Fetches the user info from the LinkedIn API
|
|
79
|
-
*/
|
|
80
|
-
async getUserInfo(token, callback) {
|
|
81
|
-
let url = this.config.userInfoUrl || this.userInfoUrl;
|
|
82
|
-
const request = this.getAuthenticatedRequest(url, token);
|
|
83
|
-
request.param('projection', '(id,localizedLastName,localizedFirstName,vanityName,profilePicture(displayImage~digitalmediaAsset:playableStreams))');
|
|
84
|
-
if (typeof callback === 'function') {
|
|
85
|
-
callback(request);
|
|
86
|
-
}
|
|
87
|
-
const body = await request.get();
|
|
88
|
-
/**
|
|
89
|
-
* Finding the user avatar
|
|
90
|
-
*/
|
|
91
|
-
let avatar = '';
|
|
92
|
-
if (body.profilePicture) {
|
|
93
|
-
const avatars = body.profilePicture['displayImage~']['elements'] || [];
|
|
94
|
-
if (avatars.length && avatars[0].identifiers && avatars[0].identifiers.length) {
|
|
95
|
-
avatar = avatars[0].identifiers[0].identifier;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
id: body.id,
|
|
100
|
-
nickName: body.vanityName || `${body.localizedFirstName} ${body.localizedLastName}`,
|
|
101
|
-
name: `${body.localizedFirstName} ${body.localizedLastName}`,
|
|
102
|
-
avatarUrl: avatar,
|
|
103
|
-
original: body,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Fetches the user email from the LinkedIn API
|
|
108
|
-
*/
|
|
109
|
-
async getUserEmail(token, callback) {
|
|
110
|
-
let url = this.config.userEmailUrl || this.userEmailUrl;
|
|
111
|
-
const request = this.getAuthenticatedRequest(url, token);
|
|
112
|
-
request.param('q', 'members');
|
|
113
|
-
request.param('projection', '(elements*(primary,type,handle~))');
|
|
114
|
-
if (typeof callback === 'function') {
|
|
115
|
-
callback(request);
|
|
116
|
-
}
|
|
117
|
-
const body = await request.get();
|
|
118
|
-
let mainEmail = body.elements.find((resource) => {
|
|
119
|
-
return resource.type === 'EMAIL' && resource['handle~'];
|
|
120
|
-
});
|
|
121
|
-
/**
|
|
122
|
-
* We except email to always exist
|
|
123
|
-
*/
|
|
124
|
-
if (!mainEmail) {
|
|
125
|
-
throw new Exception('Cannot request user email. Make sure you are using the "r_emailaddress" scope');
|
|
126
|
-
}
|
|
127
|
-
return mainEmail['handle~']['emailAddress'];
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Find if the current error code is for access denied
|
|
131
|
-
*/
|
|
132
|
-
accessDenied() {
|
|
133
|
-
const error = this.getError();
|
|
134
|
-
if (!error) {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
return error === 'user_cancelled_login' || error === 'user_cancelled_authorize';
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Returns details for the authorized user
|
|
141
|
-
*/
|
|
142
|
-
async user(callback) {
|
|
143
|
-
const token = await this.accessToken(callback);
|
|
144
|
-
const user = await this.getUserInfo(token.token, callback);
|
|
145
|
-
const email = await this.getUserEmail(token.token, callback);
|
|
146
|
-
return {
|
|
147
|
-
...user,
|
|
148
|
-
email: email,
|
|
149
|
-
emailVerificationState: 'unsupported',
|
|
150
|
-
token: token,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Finds the user by the access token
|
|
155
|
-
*/
|
|
156
|
-
async userFromToken(token, callback) {
|
|
157
|
-
const user = await this.getUserInfo(token, callback);
|
|
158
|
-
const email = await this.getUserEmail(token, callback);
|
|
159
|
-
return {
|
|
160
|
-
...user,
|
|
161
|
-
email: email,
|
|
162
|
-
emailVerificationState: 'unsupported',
|
|
163
|
-
token: { token, type: 'bearer' },
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @adonisjs/ally
|
|
3
|
-
*
|
|
4
|
-
* (c) AdonisJS
|
|
5
|
-
*
|
|
6
|
-
* For the full copyright and license information, please view the LICENSE
|
|
7
|
-
* file that was distributed with this source code.
|
|
8
|
-
*/
|
|
9
|
-
import { Oauth2Driver } from '../abstract_drivers/oauth2.js';
|
|
10
|
-
/**
|
|
11
|
-
* Spotify driver to login user via Spotify
|
|
12
|
-
*/
|
|
13
|
-
export class SpotifyDriver extends Oauth2Driver {
|
|
14
|
-
config;
|
|
15
|
-
accessTokenUrl = 'https://accounts.spotify.com/api/token';
|
|
16
|
-
authorizeUrl = 'https://accounts.spotify.com/authorize';
|
|
17
|
-
userInfoUrl = 'https://api.spotify.com/v1/me';
|
|
18
|
-
/**
|
|
19
|
-
* The param name for the authorization code
|
|
20
|
-
*/
|
|
21
|
-
codeParamName = 'code';
|
|
22
|
-
/**
|
|
23
|
-
* The param name for the error
|
|
24
|
-
*/
|
|
25
|
-
errorParamName = 'error';
|
|
26
|
-
/**
|
|
27
|
-
* Cookie name for storing the "spotify_oauth_state"
|
|
28
|
-
*/
|
|
29
|
-
stateCookieName = 'spotify_oauth_state';
|
|
30
|
-
/**
|
|
31
|
-
* Parameter name to be used for sending and receiving the state
|
|
32
|
-
* from Spotify
|
|
33
|
-
*/
|
|
34
|
-
stateParamName = 'state';
|
|
35
|
-
/**
|
|
36
|
-
* Parameter name for defining the scopes
|
|
37
|
-
*/
|
|
38
|
-
scopeParamName = 'scope';
|
|
39
|
-
/**
|
|
40
|
-
* Scopes separator
|
|
41
|
-
*/
|
|
42
|
-
scopesSeparator = ' ';
|
|
43
|
-
constructor(ctx, config) {
|
|
44
|
-
super(ctx, config);
|
|
45
|
-
this.config = config;
|
|
46
|
-
/**
|
|
47
|
-
* Extremely important to call the following method to clear the
|
|
48
|
-
* state set by the redirect request
|
|
49
|
-
*/
|
|
50
|
-
this.loadState();
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Configuring the redirect request with defaults
|
|
54
|
-
*/
|
|
55
|
-
configureRedirectRequest(request) {
|
|
56
|
-
/**
|
|
57
|
-
* Define user defined scopes or the default one's
|
|
58
|
-
*/
|
|
59
|
-
request.scopes(this.config.scopes || ['user-read-email']);
|
|
60
|
-
request.param('response_type', 'code');
|
|
61
|
-
request.param('grant_type', 'authorization_code');
|
|
62
|
-
/**
|
|
63
|
-
* Define params based upon user config
|
|
64
|
-
*/
|
|
65
|
-
if (this.config.showDialog) {
|
|
66
|
-
request.param('show_dialog', this.config.showDialog);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Returns the HTTP request with the authorization header set
|
|
71
|
-
*/
|
|
72
|
-
getAuthenticatedRequest(url, token) {
|
|
73
|
-
const request = this.httpClient(url);
|
|
74
|
-
request.header('Authorization', `Bearer ${token}`);
|
|
75
|
-
request.header('Accept', 'application/json');
|
|
76
|
-
request.parseAs('json');
|
|
77
|
-
return request;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Fetches the user info from the Spotify API
|
|
81
|
-
* https://discord.com/developers/docs/resources/user#get-current-user
|
|
82
|
-
*/
|
|
83
|
-
async getUserInfo(token, callback) {
|
|
84
|
-
const request = this.getAuthenticatedRequest(this.userInfoUrl, token);
|
|
85
|
-
if (typeof callback === 'function') {
|
|
86
|
-
callback(request);
|
|
87
|
-
}
|
|
88
|
-
const body = await request.get();
|
|
89
|
-
return {
|
|
90
|
-
id: body.id,
|
|
91
|
-
nickName: body.display_name,
|
|
92
|
-
name: body.display_name,
|
|
93
|
-
email: body.email,
|
|
94
|
-
avatarUrl: body.images[0]?.url || null,
|
|
95
|
-
emailVerificationState: 'unsupported',
|
|
96
|
-
original: body,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Find if the current error code is for access denied
|
|
101
|
-
*/
|
|
102
|
-
accessDenied() {
|
|
103
|
-
const error = this.getError();
|
|
104
|
-
if (!error) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
return error === 'access_denied';
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Returns details for the authorized user
|
|
111
|
-
*/
|
|
112
|
-
async user(callback) {
|
|
113
|
-
const token = await this.accessToken(callback);
|
|
114
|
-
const user = await this.getUserInfo(token.token, callback);
|
|
115
|
-
return {
|
|
116
|
-
...user,
|
|
117
|
-
token,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Finds the user by the access token
|
|
122
|
-
*/
|
|
123
|
-
async userFromToken(token, callback) {
|
|
124
|
-
const user = await this.getUserInfo(token, callback);
|
|
125
|
-
return {
|
|
126
|
-
...user,
|
|
127
|
-
token: { token, type: 'bearer' },
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|