-
Notifications
You must be signed in to change notification settings - Fork 9
/
linkedin-server.js
175 lines (156 loc) · 4.03 KB
/
linkedin-server.js
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
Linkedin = {}
const getImage = profilePicture => {
const image = []
if (profilePicture !== undefined){
for (const element of profilePicture['displayImage~'].elements) {
for (const identifier of element.identifiers) {
image.push(identifier.identifier)
}
}
}
return {
displayImage: profilePicture ? profilePicture.displayImage : null,
identifiersUrl: image
}
}
// Request for email, returns array
const getEmails = function(accessToken) {
const url = encodeURI(
`https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))&oauth2_access_token=${accessToken}`,
)
const response = HTTP.get(url).data
const emails = []
for (const element of response.elements) {
emails.push(element['handle~'].emailAddress)
}
return emails
}
// checks whether a string parses as JSON
const isJSON = function(str) {
try {
JSON.parse(str)
return true
} catch (e) {
return false
}
}
// returns an object containing:
// - accessToken
// - expiresIn: lifetime of token in seconds
const getTokenResponse = function(query) {
const config = ServiceConfiguration.configurations.findOne(
{ service: 'linkedin' },
)
if (!config)
throw new ServiceConfiguration.ConfigError(
'Service not configured',
)
let responseContent
try {
// Request an access token
responseContent = HTTP.post(
'https://api.linkedin.com/uas/oauth2/accessToken',
{
params: {
grant_type: 'authorization_code',
client_id: config.clientId,
client_secret: OAuth.openSecret(config.secret),
code: query.code,
redirect_uri: OAuth._redirectUri(
'linkedin',
config,
),
},
},
).content
} catch (err) {
throw new Error(
`Failed to complete OAuth handshake with Linkedin. ${
err.message
}`,
)
}
// If 'responseContent' does not parse as JSON, it is an error.
if (!isJSON(responseContent)) {
throw new Error(
`Failed to complete OAuth handshake with Linkedin. ${responseContent}`,
)
}
// Success! Extract access token and expiration
const parsedResponse = JSON.parse(responseContent)
const accessToken = parsedResponse.access_token
const expiresIn = parsedResponse.expires_in
if (!accessToken) {
throw new Error(
'Failed to complete OAuth handshake with Linkedin ' +
`-- can't find access token in HTTP response. ${responseContent}`,
)
}
return {
accessToken,
expiresIn,
}
}
// Request available fields from r_liteprofile
const getIdentity = function(accessToken) {
try {
const url = encodeURI(
`https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))&oauth2_access_token=${accessToken}`,
)
return HTTP.get(url).data
} catch (err) {
throw new Error(
`Failed to fetch identity from Linkedin. ${
err.message
}`,
)
}
}
OAuth.registerService('linkedin', 2, null, query => {
const response = getTokenResponse(query)
const accessToken = response.accessToken
const identity = getIdentity(accessToken)
const {
id,
firstName,
lastName,
profilePicture,
} = identity
if (!id) {
throw new Error('Linkedin did not provide an id')
}
const serviceData = {
id,
accessToken,
expiresAt: +new Date() + 1000 * response.expiresIn,
}
const emails = getEmails(accessToken)
const fields = {
linkedinId: id,
firstName,
lastName,
profilePicture: getImage(profilePicture),
emails,
}
if (emails.length) {
const primaryEmail = emails[0]
fields.emailAddress = primaryEmail // for backward compatibility with previous versions of this package
fields.email = primaryEmail
}
_.extend(serviceData, fields)
return {
serviceData,
options: {
profile: fields,
},
}
})
Linkedin.retrieveCredential = function(
credentialToken,
credentialSecret,
) {
return OAuth.retrieveCredential(
credentialToken,
credentialSecret,
)
}