import { Micropub, MicropubChannel, MF2 } from "./micropub_api.js"; const channel_select_radio = document.getElementById("select_channels") as HTMLInputElement; channel_select_radio.onclick = async () => { function populate_channel_list(channels: MicropubChannel[]) { (document.getElementById("channels") as HTMLElement).style.display = "block"; const channel_list = document.getElementById("channels_target") as HTMLElement; channel_list.innerHTML = ""; channels.forEach((channel) => { const template = (document.getElementById("channel_selector") as HTMLTemplateElement).content.cloneNode(true) as HTMLElement; const input = template.querySelector("input") as HTMLInputElement; const label = template.querySelector("label") as HTMLLabelElement; input.id = `channel_selector_option_${channel.uid}` input.value = channel.uid label.htmlFor = input.id label.innerHTML = `${channel.name}` channel_list.appendChild(template) }) } if (micropub == null) { throw new Error("need to authenticate first"); } const config = await micropub.config(); if (config.channels !== undefined) { populate_channel_list(config.channels) } } const no_channel_radio = document.getElementById("no_channel") as HTMLInputElement; no_channel_radio.onclick = () => { (document.getElementById("channels") as HTMLElement).style.display = "none"; const channel_list = document.getElementById("channels_target") as HTMLElement channel_list.innerHTML = ""; } const main_form = document.getElementById("micropub") as HTMLFormElement; main_form.onsubmit = async (event) => { function construct_body(form: HTMLFormElement): MF2 { let content = (form.elements.namedItem("content") as HTMLInputElement).value; let name: string | undefined = (form.elements.namedItem("name") as HTMLInputElement).value || undefined; let category: string[] = (form.elements.namedItem("category") as HTMLInputElement).value .split(",") .map(val => val.trim()); let channel: string[] | undefined = undefined; let channel_select = (form.elements.namedItem("channel_select") as HTMLInputElement).value; if (channel_select) { let channel_selector = form.elements.namedItem("channel"); if (channel_selector instanceof RadioNodeList) { channel = (Array.from(channel_selector) as HTMLInputElement[]) .map(i => i.checked ? i.value : false) .filter(i => i) as string[]; } else if (channel_selector instanceof HTMLInputElement) { channel = [channel_selector.value] } } return { type: ["h-entry"], properties: { content: [content], name: name ? [name] : undefined, category: category.length ? category : undefined, channel: channel ? channel : undefined } } } event.preventDefault() const mf2 = construct_body(main_form); console.log(JSON.stringify(mf2)); if (micropub == null) { throw new Error("need to authenticate first"); } try { const location = await micropub.submit(mf2); main_form.clear() window.open(location, "_blank") } catch (e) { console.error(e) alert(`Error: ${e}`) return } } const indieauth_form = document.getElementById("indieauth") as HTMLFormElement; indieauth_form.onsubmit = async (event) => { event.preventDefault() const form = event.target as HTMLFormElement; const me = (form.elements.namedItem("me") as HTMLInputElement).value; if (me != null) { const { discover_endpoints, create_verifier, create_challenge } = await import("./indieauth.js"); const endpoints = await discover_endpoints(new URL(me)); if (endpoints != null) { localStorage.setItem("micropub_endpoint", endpoints.micropub.toString()) localStorage.setItem("token_endpoint", endpoints.token_endpoint.toString()) if (endpoints.revocation_endpoint != null) { localStorage.setItem("revocation_endpoint", endpoints.revocation_endpoint.toString()) } } else { alert("Your website doesn't support Micropub.") return } (document.getElementById("unauthorized") as HTMLElement).style.display = "none"; (document.getElementById("authorizing") as HTMLElement).style.display = "block"; const url = endpoints.authorization_endpoint; let params = new URLSearchParams(); for (const [key, val] of url.searchParams) { params.append(key, val) } params.set("client_id", window.location.href) params.set("redirect_uri", window.location.href) params.set("response_type", "code") params.set("scope", "profile create media") params.set("state", "awoo") const code_verifier = create_verifier() localStorage.setItem("code_verifier", code_verifier) params.set("code_challenge", await create_challenge(code_verifier)) params.set("code_challenge_method", "S256") url.search = "?" + params.toString() console.log(url) window.location.href = url.toString() } } if (window.location.search != "") { (document.getElementById("authorizing") as HTMLElement).style.display = "block"; const params = new URLSearchParams(window.location.search) if (params.has("code") && params.has("state")) { const token_endpoint = new URL(localStorage.getItem("token_endpoint")!) const state = params.get("state") // XXX check state const client_id = new URL(window.location.href); client_id.search = ""; const form = new URLSearchParams(); form.set("grant_type", "authorization_code") form.set("code", params.get("code")!) form.set("client_id", client_id.toString()) form.set("redirect_uri", client_id.toString()) form.set("code_verifier", localStorage.getItem("code_verifier")!) const response = await fetch(token_endpoint, { method: "POST", headers: { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded" }, body: form.toString() }); const grant = await response.json(); // TODO: refresh tokens? if ("access_token" in grant) { localStorage.setItem("access_token", grant.access_token); (document.getElementById("authorizing") as HTMLElement).style.display = "none"; } } } let micropub: Micropub | null = null; const token = localStorage.getItem("access_token") const endpoint = localStorage.getItem("micropub_endpoint") if (token == null || endpoint == null) { (document.getElementById("unauthorized") as HTMLElement).style.display = "block"; } else { // TODO: check token validity micropub = new Micropub({ endpoint: new URL(endpoint), token }); (document.getElementById("authorized") as HTMLElement).style.display = "block"; }