Skip to content

Commit

Permalink
Merge pull request #27 from cglatot/proper-authentication-method
Browse files Browse the repository at this point in the history
Implement proper Plex login method
  • Loading branch information
cglatot authored Oct 8, 2020
2 parents 5212862 + 44898da commit e44b0d4
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 107 deletions.
8 changes: 8 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ label, p {
display: none;
}

#new-pin-container {
display: none;
}

#waitOnPinAuth {
display: none;
}

/*==========================
MODALS
==========================*/
Expand Down
24 changes: 10 additions & 14 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ <h5 class="modal-title" id="progressModalTitle"></h5>
<div id="pinOrAuthBtns" class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary active">
<input type="radio" name="pinOrAuth" value="showPinControls" id="showPinControls" autocomplete="off"
checked> PIN Authentication
checked> Plex Login
</label>
<label class="btn btn-secondary">
<input type="radio" name="pinOrAuth" value="showUrlControls" id="showUrlControls" autocomplete="off">
Expand All @@ -216,19 +216,16 @@ <h5 class="modal-title" id="progressModalTitle"></h5>
</button>
</div>
<!-- / WARNING BOX -->
<!-- PIN AUTHENTICATION -->
<div id="pin-auth-over-container" class="mt-4">
<div id="new-pin-container">
<p>Please go to <a href="https://www.plex.tv/pin" target="_blank">https://www.plex.tv/pin</a> and enter the following PIN:</p>
<div class="d-inline-flex flex-row align-items-center">
<h1 id="pin-code-holder"></h1>
<div class="spinner-border spinner-border-sm text-warning ml-2" role="status" aria-hidden="true"></div>
</div>
<!-- PLEX AUTHENTICATION -->
<div id="pin-auth-over-container" class="row mt-4">
<div id="new-pin-container" class="col pl-5 pr-5">
<button id="loginWithPlexBtn" type="button" class="btn btn-secondary btn-lg btn-block" onclick="authenticateWithPlex()">Login with Plex</button>
<div id="waitOnPinAuth" class="spinner-border spinner-border-lg text-warning" role="status" aria-hidden="true"></div>
</div>
<div id="authed-pin-container">
<p>You are authenticated via PIN.
<p>You are logged in as: <strong id="loggedInAs"></strong>
<small id="forgetPinDetails">
<a href="javascript:void(0)" onclick="forgetPinDetails()">Click here to logout.</a>
<a href="javascript:void(0)" class="ml-2" onclick="forgetPinDetails()">Click here to logout.</a>
<i id="confirmForgetPin" class="fas fa-check" style="color: #28a745; font-size: 1.5em"></i>
</small>
</p>
Expand All @@ -244,7 +241,7 @@ <h1 id="pin-code-holder"></h1>
</div>

</div>
<!-- / PIN AUTHENTICATION -->
<!-- / PLEX AUTHENTICATION -->
<!-- URL / TOKEN AUTHENTICATION -->
<div id="url-auth-over-container" class="mt-4">
<div class="form-group">
Expand Down Expand Up @@ -320,7 +317,6 @@ <h3>Plex Servers</h3>
<div class="row mt-4">
<div class="col">
<h3>Plex Libraries</h3>
<small>Choose <strong>only</strong> episodic content (TV Shows, Anime, etc). This does not work for Movies.</small>
<div class="table-responsive">
<table id="libraryTable" class="table table-hover mt-3">
<thead>
Expand Down Expand Up @@ -489,7 +485,7 @@ <h3>Episodes</h3>
<!-- MOVIE NAME -->
<div id="movieNamePlaceholder" class="row mt-4">
<div class="col">
<h2>Baby Driver</h2>
<h2></h2>
</div>
</div>
<!-- / MOVIE NAME -->
Expand Down
202 changes: 109 additions & 93 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Variables for the Authorised Devices card
var clientIdentifier; // UID for the device being used
var plexProduct = "PASTA"; // X-Plex-Product - Application name
var pastaVersion = "1.4.1"; // X-Plex-Version - Application version
var pastaVersion = "1.5.0"; // X-Plex-Version - Application version
var pastaPlatform; // X-Plex-Platform - Web Browser
var pastaPlatformVersion; // X-Plex-Platform-Version - Web Browser version
var deviceInfo; // X-Plex-Device - Operation system?
Expand All @@ -28,39 +28,33 @@ $(document).ready(() => {

// Enable Tooltips
$('.helpButtons, #titleLogo').tooltip();

// Enable history tracking for tabs
$('a[data-toggle="tab"]').historyTabs();

// Check if the page was loaded locally or over http and warn them about the value of https
if ((location.protocol == "http:") || (location.protocol == "file:")) {
if (localStorage.showHttpAlert == 'false') {

}
if (localStorage.showHttpAlert == 'false') {}
else {
$("#insecureWarning").show();
}
}

// Check if they have permanently dismissed the Login Info alert
if (localStorage.showLoginInfoAlert == 'false') {
console.log("infoalert is false");
}
if (localStorage.showLoginInfoAlert == 'false') {}
else {
$("#loginInfoAlert").show();
}

// Override the close mechanism to not show the loginInfoAlert
$("#loginInfoAlertClose").on("click", () => {
console.log('Entered the click for close');
hideLoginInfoAlertForever();
});

// SET THE VARIABLES FOR PLEX PIN AUTH REQUESTS
try {
let browserInfo = getBrowser();
// Set the clientID, this might get overridden if one is saved to localstorage
clientIdentifier = `PASTA-cglatot-${Date.now()}-${Math.round(Math.random() * 1000)}`;
clientIdentifier = localStorage.clientIdentifier || `PASTA-cglatot-${Date.now()}-${Math.round(Math.random() * 1000)}`;
// Set the OS
deviceInfo = browserInfo.os || "";
// Set the web browser and version
Expand All @@ -72,7 +66,7 @@ $(document).ready(() => {
console.log(e);
// Fallback values
// Set the clientID, this might get overridden if one is saved to localstorage
clientIdentifier = `PASTA-cglatot-${Date.now()}-${Math.round(Math.random() * 1000)}`;
clientIdentifier = localStorage.clientIdentifier || `PASTA-cglatot-${Date.now()}-${Math.round(Math.random() * 1000)}`;
// Set the OS
deviceInfo = "";
// Set the web browser and version
Expand All @@ -86,7 +80,6 @@ $(document).ready(() => {
$('#plexUrl').on("input", () => {
validateEnableConnectBtn('plexUrl');
});

// Validation listeners on the Plex Token Input
$('#plexToken').on("input", () => {
validateEnableConnectBtn('plexToken');
Expand All @@ -97,63 +90,130 @@ $(document).ready(() => {
toggleAuthPages(this.value);
});

// Check whether they want to connect using a local IP or not
if (localStorage.useLocalAddress == "true") {
$('#connectViaLocalAddress').prop('checked', true);
} else {
$('#connectViaLocalAddress').prop('checked', false);
}

if (!localStorage.isPinAuth) {
// Not using PIN auth, so must be using url / token
if (localStorage.plexUrl && localStorage.plexUrl !== "") {
plexUrl = localStorage.plexUrl;
$('#plexUrl').val(localStorage.plexUrl);
validateEnableConnectBtn('plexUrl');
$('#forgetDivider, #forgetDetailsSection').show();
// Check if there is a stored Auth Token
if (localStorage.pinAuthToken) {
checkIfAuthTokenIsValid();
} else {
$('#new-pin-container').show();
}
});

// Checks if the generated token is valid
function checkIfAuthTokenIsValid() {
$.ajax({
"url": `https://plex.tv/api/v2/user`,
"headers": {
"accept": "application/json",
"X-Plex-Client-Identifier": clientIdentifier,
"X-Plex-Token": localStorage.pinAuthToken,
"X-Plex-Product": plexProduct,
"X-Plex-Version": pastaVersion,
"X-Plex-Platform": pastaPlatform,
"X-Plex-Platform-Version": pastaPlatformVersion,
"X-Plex-Device": deviceInfo,
"X-Plex-Device-Name": deviceName
},
"method": "GET",
"success": (data) => {
console.log(data);
plexToken = localStorage.pinAuthToken;
$('#new-pin-container').hide();
$('#authed-pin-container').show();
$('#loggedInAs').text(data.username);
getServers();
},
"error": (data, statusText, xhr) => {
console.log("ERROR L121");
console.log(data.status);
if (data.status == 401) {
// Auth Token has expired
localStorage.removeItem('isPinAuth');
localStorage.removeItem('pinAuthToken');
localStorage.removeItem('useLocalAddress');
$('#new-pin-container').show();
}
}
if (localStorage.plexToken && localStorage.plexToken !== "") {
plexToken = localStorage.plexToken;
$('#plexToken').val(localStorage.plexToken);
validateEnableConnectBtn('plexToken');
$('#forgetDivider, #forgetDetailsSection').show();
});
}

function authenticateWithPlex() {
// Generate a PIN code to get the URL
$.ajax({
"url": `https://plex.tv/api/v2/pins`,
"headers": {
"accept": "application/json",
"strong": "true",
"X-Plex-Client-Identifier": clientIdentifier,
"X-Plex-Product": plexProduct,
"X-Plex-Version": pastaVersion,
"X-Plex-Platform": pastaPlatform,
"X-Plex-Platform-Version": pastaPlatformVersion,
"X-Plex-Device": deviceInfo,
"X-Plex-Device-Name": deviceName
},
"method": "POST",
"success": (data) => {
// For some reason auth doesn't work unless you choose Plex Web as the product id
let plexProductTemp = encodeURIComponent("Plex Web");
let authAppUrl = `https://app.plex.tv/auth#?clientID=${clientIdentifier}&code=${data.code}&context%5Bdevice%5D%5Bproduct%5D=${plexProductTemp}`;

$('#waitOnPinAuth').show();
$('#loginWithPlexBtn').hide();
window.open(authAppUrl, 'PlexSignIn', 'width=800,height=730');
backOffTimer = Date.now();
listenForValidPincode(data.id, clientIdentifier, data.code);
},
"error": (data) => {
console.log("ERROR L121");
console.log(data);
}
});
}

// Display a PIN code for that authentication as well
function listenForValidPincode(pinId, clientId, pinCode) {
let currentTime = Date.now();
if ((currentTime - backOffTimer)/1000 < 10) {
$.ajax({
"url": `https://plex.tv/pins.xml`,
"url": `https://plex.tv/api/v2/pins/${pinId}`,
"headers": {
"X-Plex-Client-Identifier": clientIdentifier,
"X-Plex-Product": plexProduct,
"X-Plex-Version": pastaVersion,
"X-Plex-Platform": pastaPlatform,
"X-Plex-Platform-Version": pastaPlatformVersion,
"X-Plex-Device": deviceInfo,
"X-Plex-Device-Name": deviceName
"accept": "application/json",
"code": pinCode,
"X-Plex-Client-Identifier": clientId,
},
"method": "POST",
"method": "GET",
"success": (data) => {
let pinId = $(data).find('id')[0].innerHTML;
let pinCode = $(data).find('code')[0].innerHTML;

$('#pin-code-holder').html(pinCode);
backOffTimer = Date.now();
listenForValidPincode(pinId);
if (data.authToken != null) {
$('#waitOnPinAuth').hide();
localStorage.clientIdentifier = clientIdentifier;
localStorage.isPinAuth = true;
localStorage.pinAuthToken = data.authToken;
plexToken = data.authToken;
checkIfAuthTokenIsValid();
} else {
setTimeout(() => {
listenForValidPincode(pinId, clientId, pinCode);
}, 3000); // Check every 3 seconds
}
},
"error": (data) => {
console.log("ERROR L121");
console.log(data);
}
});
} else {
$('#new-pin-container').hide();
$('#authed-pin-container').show();
// We are using Pin Auth
clientIdentifier = localStorage.clientIdentifier;
plexToken = localStorage.pinAuthToken;
getServers();
$('#new-pin-container').html(' <p><i class="far fa-times-circle mr-2" style="color: #e5a00d; font-size: 1.5em; vertical-align: middle;"></i>Login timed out. \
Please <a href="javascript:void(0)" onclick="window.location.reload()">refresh the page</a> and ensure your popup blocker is disabled.</p>');
}
});
}

// Toggle between the authentication methods
function toggleAuthPages(value) {
if (value == 'showPinControls') {
$('#pin-auth-over-container').show();
Expand All @@ -164,7 +224,7 @@ function toggleAuthPages(value) {

if (localStorage.isPinAuth) {
$("#authWarningText").html(`<div class="alert alert-warning alert-dismissible fade show mt-3" role="alert">
<strong>Warning:</strong> You are currently signed in via PIN. Please <a href="javascript:void(0)" onclick="forgetPinDetails()">sign out of PIN</a> before proceeding to connect using a URL / IP address.
<strong>Warning:</strong> You are currently signed in via Plex. Please <a href="javascript:void(0)" onclick="forgetPinDetails()">sign out of Plex</a> before proceeding to connect using a URL / IP address.
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
Expand All @@ -173,56 +233,13 @@ function toggleAuthPages(value) {
}
}

function listenForValidPincode (pinId) {
let currentTime = Date.now();
if ((currentTime - backOffTimer)/1000 < 180) {
$.ajax({
"url": `https://plex.tv/pins/${pinId}`,
"headers": {
"X-Plex-Client-Identifier": clientIdentifier,
"X-Plex-Product": plexProduct,
"X-Plex-Version": pastaVersion,
"X-Plex-Platform": pastaPlatform,
"X-Plex-Platform-Version": pastaPlatformVersion,
"X-Plex-Device": deviceInfo,
"X-Plex-Device-Name": deviceName
},
"method": "GET",
"success": (data) => {
if (data.pin.auth_token != null) {
plexToken = data.pin.auth_token;
// Save to local storage
localStorage.isPinAuth = true;
localStorage.pinAuthToken = plexToken;
localStorage.clientIdentifier = clientIdentifier;
$('#new-pin-container').hide();
$('#authed-pin-container').show();
getServers();
} else {
setTimeout(() => {
listenForValidPincode(pinId);
}, 5000);
}
},
"error": (data) => {
console.log("ERROR L186");
console.log(data);
return;
}
});
} else {
$('#new-pin-container').html(' <p><i class="far fa-times-circle mr-2" style="color: #e5a00d; font-size: 1.5em; vertical-align: middle;"></i>PIN entry timed out. \
Please <a href="javascript:void(0)" onclick="window.location.reload()">refresh the page</a> to get a new PIN.</p>');
}
}

// Called when the "connect using local IP" checkbox is toggled
// Refreshes the page and updates the variable for whether it should use the local address or not
function useLocalAddress (checkbox) {
if (checkbox.checked) {
localStorage.useLocalAddress = "true";
} else {
localStorage.useLocalAddress = "false";
localStorage.removeItem('useLocalAddress');
}
window.location.reload();
}
Expand Down Expand Up @@ -358,7 +375,6 @@ function forgetDetails() {
function forgetPinDetails() {
localStorage.removeItem('isPinAuth');
localStorage.removeItem('pinAuthToken');
localStorage.removeItem('clientIdentifier');
localStorage.removeItem('useLocalAddress');
window.location.reload();
}
Expand Down

0 comments on commit e44b0d4

Please sign in to comment.