Plex Home: the owner's PIN is asked for and checked by plex.tv when switching back, wrong guesses are slowed down
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d813884074
commit
b171f35be6
3 files changed
+36
-9
No files matched your search
@@ -241,6 +241,7 @@ async function plexTvAny(path, token, opts = {}) {
|
||||
}
|
||||
const truthy = v => v === true || v === 1 || v === '1' || v === 'true';
|
||||
/** The people in this Plex Home: [{ id, title, thumb, admin, protected, restricted, guest }]. */
|
||||
const plexPinFails = new Map(); // hub person + Plex person -> wrong guesses
|
||||
async function plexHomeUsers(token) {
|
||||
const { json, text } = await plexTvAny('/api/home/users', token);
|
||||
const raw = json ? (json.users || json.MediaContainer?.User || json.User || []) : [...text.matchAll(/<User\b[^>]*>/g)].map(m => attrs(m[0]));
|
||||
@@ -363,19 +364,32 @@ async function plexApi(req, res) {
|
||||
const owner = st.mainToken || token;
|
||||
const target = (await plexHomeUsers(owner)).find(x => x.id === String(id));
|
||||
if (!target) return json(res, 404, { error: 'That person is not in your Plex Home' });
|
||||
if (target.admin && !st.mainToken) { plexSave({ ...st, user: { id: target.id, title: target.title, thumb: target.thumb, admin: true } }); return json(res, 200, { ok: true, user: { id: target.id, title: target.title, thumb: target.thumb, admin: true } }); } // already the account that signed in
|
||||
const meNow = st.user ? String(st.user.id) : (target.admin && !st.mainToken ? target.id : '');
|
||||
const same = meNow === target.id; // already using Plex as this person: nothing to prove
|
||||
// Anyone with a PIN in Plex (the owner included) needs it every time you switch to them; plex.tv checks it, and wrong guesses are slowed down here.
|
||||
const gate = (users.current() ? users.current().id : '') + ':' + target.id, fails = plexPinFails.get(gate) || { n: 0, until: 0 };
|
||||
if (target.protected && !same) {
|
||||
if (fails.until > Date.now()) return json(res, 429, { error: `Too many wrong PINs. Try again in ${Math.ceil((fails.until - Date.now()) / 60000)} min.` });
|
||||
if (!pin) return json(res, 403, { error: 'That PIN is not right' });
|
||||
}
|
||||
let userToken;
|
||||
if (target.admin && st.mainToken) userToken = st.mainToken; // back to the account that signed in: no PIN needed
|
||||
if (same) userToken = target.admin && st.mainToken ? st.mainToken : st.token;
|
||||
else if (target.admin && st.mainToken && !target.protected) userToken = st.mainToken; // back to the account that signed in, which has no PIN
|
||||
else {
|
||||
try {
|
||||
const q = pin ? '?' + new URLSearchParams({ pin: String(pin).slice(0, 8) }) : '';
|
||||
const { json: j, text } = await plexTvAny(`/api/home/users/${encodeURIComponent(target.id)}/switch${q}`, owner, { method: 'POST' });
|
||||
userToken = (j && (j.authToken || j.authenticationToken || (j.user && (j.user.authToken || j.user.authenticationToken)))) || (text.match(/authenticationToken="([^"]+)"/) || [])[1];
|
||||
} catch (e) {
|
||||
if (e.status === 401 || e.status === 403) return json(res, 403, { error: target.protected || pin ? 'That PIN is not right' : 'Plex would not switch to that person' });
|
||||
if (e.status === 401 || e.status === 403) {
|
||||
if (target.protected) { fails.n++; if (fails.n >= 5) { fails.until = Date.now() + 10 * 60e3; fails.n = 0; } plexPinFails.set(gate, fails); }
|
||||
return json(res, 403, { error: target.protected || pin ? 'That PIN is not right' : 'Plex would not switch to that person' });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
if (!userToken && target.admin && st.mainToken) userToken = st.mainToken; // plex.tv accepted the PIN for the owner and gave no new token: the one that signed in is theirs
|
||||
if (!userToken) return json(res, 502, { error: 'Plex did not give a sign-in for that person' });
|
||||
plexPinFails.delete(gate);
|
||||
}
|
||||
const rs = await plexTv(RESOURCES, userToken), r = rs.find(x => x.clientIdentifier === st.sid);
|
||||
if (!r) return json(res, 403, { error: target.title + ' cannot use this Plex server' });
|
||||
|
||||
Reference in new issue
Block a user