diff --git a/SSO-Auth/Api/SSOViewsController.cs b/SSO-Auth/Api/SSOViewsController.cs index 70770b5..2d66a9a 100644 --- a/SSO-Auth/Api/SSOViewsController.cs +++ b/SSO-Auth/Api/SSOViewsController.cs @@ -112,9 +112,9 @@ public class SSOViewsController : ControllerBase } /// - /// Returns the shared js module that initializes the ApiClient. + /// Get the shared js module that initializes the ApiClient. /// - /// The html view for the linking interface. + /// Returns the shared js module that initializes the ApiClient. // [Authorize(Policy = "DefaultAuthorization")] [HttpGet("ApiClient.js")] public ActionResult GetApiClientView() diff --git a/SSO-Auth/Config/linking.html b/SSO-Auth/Config/linking.html index 46beed7..1f53e7d 100644 --- a/SSO-Auth/Config/linking.html +++ b/SSO-Auth/Config/linking.html @@ -1,7 +1,15 @@ - SSO + + SSO Linking
+ + diff --git a/SSO-Auth/SSOPlugin.cs b/SSO-Auth/SSOPlugin.cs index fd612a5..5eb981e 100644 --- a/SSO-Auth/SSOPlugin.cs +++ b/SSO-Auth/SSOPlugin.cs @@ -98,6 +98,11 @@ public class SSOPlugin : BasePlugin, IPlugin, IHasWebPages Name = Name + "-linking.js", EmbeddedResourcePath = $"{GetType().Namespace}.Config.linking.js" }, + new PluginPageInfo + { + Name = Name + "-ApiClient.js", + EmbeddedResourcePath = $"{GetType().Namespace}.Views.apiClient.js" + }, }; } } diff --git a/SSO-Auth/Views/apiClient.js b/SSO-Auth/Views/apiClient.js new file mode 100644 index 0000000..307ff42 --- /dev/null +++ b/SSO-Auth/Views/apiClient.js @@ -0,0 +1,142 @@ +import jellyfinApiclient from "https://esm.run/jellyfin-apiclient"; +window.jellyfinApiclient = jellyfinApiclient; +console.log(jellyfinApiclient); + +// https://github.com/jellyfin/jellyfin-web/blob/9067b0e397cc8b38635d661ce86ddd83194f3202/src/scripts/clientUtils.js#L19-L76 +export async function serverAddress() { + const apiClient = window.ApiClient; + + if (apiClient) { + return Promise.resolve(apiClient.serverAddress()); + } + + const urls = []; + + if (urls.length === 0) { + // Otherwise use computed base URL + let url; + const index = window.location.href.toLowerCase().lastIndexOf("/web"); + if (index != -1) { + url = window.location.href.substring(0, index); + } else { + // fallback to location without path + url = window.location.origin; + } + + // Don't use bundled app URL (file:) as server URL + if (url.startsWith("file:")) { + return Promise.resolve(); + } + + urls.push(url); + } + + console.debug("URL candidates:", urls); + + const promises = urls.map((url) => { + return fetch(`${url}/System/Info/Public`) + .then((resp) => { + return { + url: url, + response: resp, + }; + }) + .catch(() => { + return Promise.resolve(); + }); + }); + + return Promise.all(promises) + .then((responses) => { + responses = responses.filter((obj) => obj && obj.response.ok); + return Promise.all( + responses.map((obj) => { + return { + url: obj.url, + config: obj.response.json(), + }; + }) + ); + }) + .then((configs) => { + const selection = + configs.find((obj) => !obj.config.StartupWizardCompleted) || configs[0]; + return Promise.resolve(selection?.url); + }) + .catch((error) => { + console.log(error); + return Promise.resolve(); + }); +} + +// TODO: Refactor duplicated code +// ! Duplicated at +// https://github.com/9p4/jellyfin-plugin-sso/blob/38558d762a13422862240af4060bdd1bb1618d57/SSO-Auth/WebResponse.cs#L363-L401 +function getDeviceName() { + return "DUMMY"; +} + +function getDeviceId() { + return localStorage.getItem("_deviceId2"); +} + +const sleep = (milliseconds) => { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +}; + +async function awaitLocalStorage() { + while ( + localStorage.getItem("_deviceId2") == null || + localStorage.getItem("jellyfin_credentials") == null || + JSON.parse(localStorage.getItem("jellyfin_credentials"))["Servers"][0][ + "Id" + ] == null + ) { + // If localStorage isn't initialized yet, try again. + await sleep(100); + } +} + +await awaitLocalStorage(); + +// Fetch credentials + +var credentials = new jellyfinApiclient.Credentials(); + +var server = await serverAddress(); +console.log({ server: server }); +var deviceId = getDeviceId(); +var appName = "SSO-Auth"; +var appVersion = "0.0.0.9000"; +var capabilities = {}; + +const current_server = credentials + .credentials() + .Servers.find((e) => e.LocalAddress == server || e.ManualAddress == server); + +var localApiClient = new jellyfinApiclient.ApiClient( + server, + appName, + appVersion, + getDeviceName(), + deviceId +); +localApiClient.setAuthenticationInfo( + current_server.AccessToken, + current_server.UserId +); + +var connections = new jellyfinApiclient.ConnectionManager( + credentials, + appName, + appVersion, + getDeviceName(), + deviceId, + capabilities +); + +connections.addApiClient(localApiClient); + +window.ApiClient = localApiClient; + +export default localApiClient;