The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/apps/meteor/packages/linkedin-oauth/linkedin-server.js

148 lines
4.0 KiB

import { fetch } from 'meteor/fetch';
import { OAuth } from 'meteor/oauth';
import { ServiceConfiguration } from 'meteor/service-configuration';
export const 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 = async function (accessToken) {
const url = encodeURI(
`https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))&oauth2_access_token=${accessToken}`,
);
const data = await fetch(url);
const response = await data.json();
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 = async function (query) {
const config = await ServiceConfiguration.configurations.findOneAsync({ service: 'linkedin' });
if (!config) throw new ServiceConfiguration.ConfigError('Service not configured');
let responseContent;
try {
// Request an access token
const request = await fetch('https://api.linkedin.com/uas/oauth2/accessToken', {
method: 'POST',
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: config.clientId,
client_secret: OAuth.openSecret(config.secret),
code: query.code,
redirect_uri: OAuth._redirectUri('linkedin', config),
}),
});
responseContent = await request.text();
} 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 = async function (accessToken) {
try {
const url = encodeURI(
`https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))&oauth2_access_token=${accessToken}`,
);
const request = await fetch(url);
return request.json();
} catch (err) {
throw new Error(`Failed to fetch identity from Linkedin. ${err.message}`);
}
};
OAuth.registerService('linkedin', 2, null, async (query) => {
const response = await getTokenResponse(query);
const { accessToken } = response;
const identity = await getIdentity(accessToken);
const { id, firstName, lastName, profilePicture } = identity;
if (!id) {
throw new Error('Linkedin did not provide an id');
}
const emails = await 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;
}
const serviceData = {
id,
accessToken,
expiresAt: +new Date() + 1000 * response.expiresIn,
...fields,
};
return {
serviceData,
options: {
profile: fields,
},
};
});
Linkedin.retrieveCredential = function (credentialToken, credentialSecret) {
return OAuth.retrieveCredential(credentialToken, credentialSecret);
};