feat(api): allow plex logins from users who have access to the server

pull/97/head
sct 4 years ago
parent 8f6247d821
commit 514714071d

@ -58,6 +58,7 @@
"@types/react-transition-group": "^4.4.0", "@types/react-transition-group": "^4.4.0",
"@types/swagger-ui-express": "^4.1.2", "@types/swagger-ui-express": "^4.1.2",
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/xml2js": "^0.4.5",
"@types/yamljs": "^0.2.31", "@types/yamljs": "^0.2.31",
"@typescript-eslint/eslint-plugin": "^4.0.0", "@typescript-eslint/eslint-plugin": "^4.0.0",
"@typescript-eslint/parser": "^3.10.1", "@typescript-eslint/parser": "^3.10.1",

@ -1,4 +1,6 @@
import axios, { AxiosInstance } from 'axios'; import axios, { AxiosInstance } from 'axios';
import xml2js from 'xml2js';
import { getSettings } from '../lib/settings';
interface PlexAccountResponse { interface PlexAccountResponse {
user: PlexUser; user: PlexUser;
@ -26,6 +28,33 @@ interface PlexUser {
entitlements: string[]; entitlements: string[];
} }
interface ServerResponse {
$: {
id: string;
serverId: string;
machineIdentifier: string;
name: string;
lastSeenAt: string;
numLibraries: string;
owned: string;
};
}
interface FriendResponse {
MediaContainer: {
User: {
$: {
id: string;
title: string;
username: string;
email: string;
thumb: string;
};
Server: ServerResponse[];
}[];
};
}
class PlexTvAPI { class PlexTvAPI {
private authToken: string; private authToken: string;
private axios: AxiosInstance; private axios: AxiosInstance;
@ -57,6 +86,48 @@ class PlexTvAPI {
throw new Error('Invalid auth token'); throw new Error('Invalid auth token');
} }
} }
public async getFriends(): Promise<FriendResponse> {
const response = await this.axios.get('/pms/friends/all', {
transformResponse: [],
responseType: 'text',
});
const parsedXml = (await xml2js.parseStringPromise(
response.data
)) as FriendResponse;
return parsedXml;
}
public async checkUserAccess(authUser: PlexUser): Promise<boolean> {
const settings = getSettings();
try {
if (!settings.plex.machineId) {
throw new Error('Plex is not configured!');
}
const friends = await this.getFriends();
const users = friends.MediaContainer.User;
const user = users.find((u) => Number(u.$.id) === authUser.id);
if (!user) {
throw new Error(
'This user does not exist on the main plex accounts shared list'
);
}
return !!user.Server.find(
(server) => server.$.machineIdentifier === settings.plex.machineId
);
} catch (e) {
console.log(`Error checking user access: ${e.message}`);
return false;
}
}
} }
export default PlexTvAPI; export default PlexTvAPI;

@ -10,7 +10,7 @@ interface Library {
interface PlexSettings { interface PlexSettings {
name: string; name: string;
machineId: string; machineId?: string;
ip: string; ip: string;
port: number; port: number;
libraries: Library[]; libraries: Library[];
@ -67,10 +67,9 @@ class Settings {
apiKey: 'temp', apiKey: 'temp',
}, },
plex: { plex: {
name: 'Main Server', name: '',
ip: '127.0.0.1', ip: '127.0.0.1',
port: 32400, port: 32400,
machineId: '',
libraries: [], libraries: [],
}, },
radarr: [], radarr: [],

@ -70,8 +70,22 @@ authRoutes.post('/login', async (req, res) => {
// If we get to this point, the user does not already exist so we need to create the // If we get to this point, the user does not already exist so we need to create the
// user _assuming_ they have access to the plex server // user _assuming_ they have access to the plex server
// (We cant do this until we finish the settings sytem and actually const mainUser = await userRepository.findOneOrFail({
// store the user token in ticket #55) select: ['id', 'plexToken'],
order: { id: 'ASC' },
});
const mainPlexTv = new PlexTvAPI(mainUser.plexToken ?? '');
if (await mainPlexTv.checkUserAccess(account)) {
user = new User({
email: account.email,
username: account.username,
plexId: account.id,
plexToken: account.authToken,
permissions: Permission.REQUEST,
avatar: account.thumb,
});
await userRepository.save(user);
}
} }
// Set logged in session // Set logged in session

@ -1845,6 +1845,13 @@
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==
"@types/xml2js@^0.4.5":
version "0.4.5"
resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.5.tgz#d21759b056f282d9c7066f15bbf5c19b908f22fa"
integrity sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==
dependencies:
"@types/node" "*"
"@types/yamljs@^0.2.31": "@types/yamljs@^0.2.31":
version "0.2.31" version "0.2.31"
resolved "https://registry.yarnpkg.com/@types/yamljs/-/yamljs-0.2.31.tgz#b1a620b115c96db7b3bfdf0cf54aee0c57139245" resolved "https://registry.yarnpkg.com/@types/yamljs/-/yamljs-0.2.31.tgz#b1a620b115c96db7b3bfdf0cf54aee0c57139245"

Loading…
Cancel
Save