"use strict"; function byId(id, nullOk=false) { const el = document.getElementById(id); if (!el && !nullOk) { console.error(`No element #${id}`); } return el; } const LOCALSTORAGE_KEY_SERVER = "mattermostServer"; const RE_SERVER_ITEM = new RegExp(`^${LOCALSTORAGE_KEY_SERVER}_(.*)\$`, "").compile(); class Storage { getServers() { let servers = []; for (var i = 0; i < window.localStorage.length; i++) { const key = window.localStorage.key(i); const matches = key.match(RE_SERVER_ITEM); if (matches) { servers.push(matches[1]); } } return servers; } _key_for(endpoint) { return `${LOCALSTORAGE_KEY_SERVER}_${endpoint}`; } clear(endpoint) { window.localStorage.removeItem(this._key_for(endpoint)); } store(endpoint, login_id, token) { window.localStorage.setItem(this._key_for(endpoint), JSON.stringify({login_id, token})); } get(endpoint) { return JSON.parse(window.localStorage.getItem(this._key_for(endpoint)) || "null"); } } class MattermostApi { constructor(endpoint) { this._endpoint = endpoint; } get id() { return this._endpoint; } async get(path, token) { const headers = token ? {"Authorization": `Bearer ${token}`} : {}; const response = await ajax.getJson(`${this._endpoint}${path}`, {headers}); if (!response.ok) { throw response; } return response; } async post(path, data, token) { const headers = token ? {"Authorization": `Bearer ${token}`} : {}; const response = await ajax.postJson(`${this._endpoint}${path}`, data, {headers}); if (!response.ok) { throw response; } return response; } } class MattermostClient { constructor (api, storage) { this.api = api; this.storage = storage; } async logIn(login_id, password) { const response = await this.api.post("/users/login", {login_id, password}); const token = response.getResponseHeader("Token"); if (!token) { throw Error("No Token header in response to log in request"); } this.storage.store(this.api.id, login_id, token); return response.responseJson; } async logOut() { const stored = this.storage.get(this.api.id); if (!stored || !stored.token) { throw Error("No token stored"); } const response = await this.api.post("/users/logout", undefined, stored.token); // Verify that the token is now invalidated let tokenWorks; try { const meResponse = await this.usersMe(); tokenWorks = true; } catch (e) { if (e instanceof ajax.NotOkError && e.xhr.status == 401) { tokenWorks = false; } else { throw e; } } if (tokenWorks) { throw new Error("Failed to log out: token still works after trying to log out"); } this.storage.clear(this.api.id); return response.responseJson; } async usersMe() { const stored = this.storage.get(this.api.id); if (!stored || !stored.token) { throw Error("No token stored"); } const response = await this.api.get("/users/me", stored.token); return response.responseJson; } async myTeams() { const response = await this.api.get("/users/me/teams", stored.token); return response.responseJson; } async myChannels(team_id) { const response = await this.api.get(`/users/me/teams/${team_id}/channels`, stored.token); return response.responseJson; } } /** * Return an endpoint URL that has a protocol, domain and path */ function normalizedEndpoint(endpoint) { let matches = endpoint.match(/^(https?:\/\/)?([^\/]+)(\/.*)?$/i); if (!matches) throw Error("Invalid endpoint URL"); let protocol = matches[1] || "https://"; let domain = matches[2]; let path = matches[3] || "/api/v4"; return `${protocol}${domain}${path}`; } function createClient(endpoint) { const api = new MattermostApi(normalizedEndpoint(endpoint)); const storage = new Storage(); return new MattermostClient(api, storage); } function buttonDisable(element, text) { element.value = text; element.disabled = true; } function buttonEnable(element, text) { element.value = text; element.disabled = false; } function logIn() { byId("user_json").innerText = ""; const client = createClient(byId("server").value); buttonDisable(byId("login"), "Logging in..."); client.logIn(byId("username").value, byId("password").value) .then(json => { buttonEnable(byId("login"), "Logged in"); byId("login_message").innerText = ""; byId("user_json").innerText = JSON.stringify(json, null, 2); }) .catch(error => { console.error(error); buttonEnable(byId("login"), "Could not log in"); byId("login_message").innerText = `${error}`; }); } function logOut() { const client = createClient(byId("server").value); buttonDisable(byId("logout"), "Logging out..."); client.logOut() .then(response => { buttonEnable(byId("logout"), "Logged out"); byId("logout_message").innerText = ""; byId("user_json").innerText = ""; }) .catch(error => { console.error(error); buttonEnable(byId("logout"), "Could not log out"); byId("logout_message").innerText = `${error}`; }); } function validateToken() { byId("user_json").innerText = ""; const client = createClient(byId("server").value); buttonDisable(byId("validate"), "Validating token..."); let cred = client.storage.get(client.api.id); if (!cred || !cred.token) { buttonEnable(byId("validate"), "No token, log in first"); return; } client.usersMe() .then(json => { buttonEnable(byId("validate"), "Validation succeeded"); byId("validate_message").innerText = ""; byId("user_json").innerText = JSON.stringify(json, null, 2); }) .catch(error => { console.error(error); buttonEnable(byId("validate"), "Validation failed"); byId("validate_message").innerText = `${error}`; }); }