add: user requests in js app sdk
This commit is contained in:
parent
884a89904e
commit
0138bf4cd4
52 changed files with 282 additions and 53 deletions
|
@ -83,6 +83,7 @@
|
|||
const search = new URLSearchParams(window.location.search);
|
||||
search.append(\"verifier\", verifier);
|
||||
search.append(\"token\", res.payload);
|
||||
search.append(\"uid\", \"{{ user.id }}\");
|
||||
|
||||
window.location.href = `{{ app.redirect|remove_script_tags|safe }}?${search.toString()}`;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,45 @@ import {
|
|||
JSONStringify as json_stringify,
|
||||
} from "https://unpkg.com/json-with-bigint@3.4.4/json-with-bigint.js";
|
||||
|
||||
export default function tetratto(tetratto_host, api_key) {
|
||||
/// PKCE key generation.
|
||||
export const PKCE = {
|
||||
/// Create a verifier for [`PKCE::challenge`].
|
||||
verifier: async (length) => {
|
||||
let text = "";
|
||||
const possible =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
text += possible.charAt(
|
||||
Math.floor(Math.random() * possible.length),
|
||||
);
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
/// Create the challenge needed to request a user token.
|
||||
challenge: async (verifier) => {
|
||||
const data = new TextEncoder().encode(verifier);
|
||||
const digest = await window.crypto.subtle.digest("SHA-256", data);
|
||||
return btoa(
|
||||
String.fromCharCode.apply(null, [...new Uint8Array(digest)]),
|
||||
)
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "");
|
||||
},
|
||||
};
|
||||
|
||||
export default function tetratto({
|
||||
host = "https://tetratto.com",
|
||||
api_key = null,
|
||||
app_id = 0n,
|
||||
user_token = null,
|
||||
user_verifier = null,
|
||||
user_id = 0n,
|
||||
}) {
|
||||
const GRANT_URL = `${host}/auth/connections_link/app/${app_id}`;
|
||||
|
||||
function api_promise(res) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (res.ok) {
|
||||
|
@ -14,11 +52,16 @@ export default function tetratto(tetratto_host, api_key) {
|
|||
});
|
||||
}
|
||||
|
||||
// app data
|
||||
async function app() {
|
||||
if (!api_key) {
|
||||
throw Error("No API key provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(`${tetratto_host}/api/v1/app_data/app`, {
|
||||
await fetch(`${host}/api/v1/app_data/app`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Atto-Secret-Key": api_key,
|
||||
|
@ -30,10 +73,14 @@ export default function tetratto(tetratto_host, api_key) {
|
|||
}
|
||||
|
||||
async function query(body) {
|
||||
if (!api_key) {
|
||||
throw Error("No API key provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(`${tetratto_host}/api/v1/app_data/query`, {
|
||||
await fetch(`${host}/api/v1/app_data/query`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
@ -47,10 +94,14 @@ export default function tetratto(tetratto_host, api_key) {
|
|||
}
|
||||
|
||||
async function insert(key, value) {
|
||||
if (!api_key) {
|
||||
throw Error("No API key provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(`${tetratto_host}/api/v1/app_data`, {
|
||||
await fetch(`${host}/api/v1/app_data`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
@ -67,10 +118,14 @@ export default function tetratto(tetratto_host, api_key) {
|
|||
}
|
||||
|
||||
async function remove(id) {
|
||||
if (!api_key) {
|
||||
throw Error("No API key provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(`${tetratto_host}/api/v1/app_data/${id}`, {
|
||||
await fetch(`${host}/api/v1/app_data/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Atto-Secret-Key": api_key,
|
||||
|
@ -82,10 +137,14 @@ export default function tetratto(tetratto_host, api_key) {
|
|||
}
|
||||
|
||||
async function remove_query(body) {
|
||||
if (!api_key) {
|
||||
throw Error("No API key provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(`${tetratto_host}/api/v1/app_data/query`, {
|
||||
await fetch(`${host}/api/v1/app_data/query`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
@ -98,11 +157,110 @@ export default function tetratto(tetratto_host, api_key) {
|
|||
);
|
||||
}
|
||||
|
||||
// user connection
|
||||
/// Extract the verifier, token, and user ID from the URL.
|
||||
function extract_verifier_token_uid() {
|
||||
const search = new URLSearchParams(window.location.search);
|
||||
return [
|
||||
search.get("verifier"),
|
||||
search.get("token"),
|
||||
BigInt(search.get("uid")),
|
||||
];
|
||||
}
|
||||
|
||||
/// Accept a connection grant and store it in localStorage.
|
||||
function localstorage_accept_connection() {
|
||||
const [verifier, token, uid] = extract_verifier_token_uid();
|
||||
window.localStorage.setItem("atto:grant.verifier", verifier);
|
||||
window.localStorage.setItem("atto:grant.token", token);
|
||||
window.localStorage.setItem("atto:grant.user_id", uid);
|
||||
}
|
||||
|
||||
async function refresh_token(verifier) {
|
||||
if (!user_token) {
|
||||
throw Error("No user token provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(
|
||||
`${host}/api/v1/auth/user/${user_id}/grants/${app_id}/refresh`,
|
||||
{
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Cookie": `__Secure-atto-token=${user_token}`,
|
||||
},
|
||||
body: json_stringify({
|
||||
verifier,
|
||||
}),
|
||||
},
|
||||
)
|
||||
).text(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async function request({
|
||||
api_path,
|
||||
method = "POST",
|
||||
content_type = "application/json",
|
||||
body = "{}",
|
||||
}) {
|
||||
if (!user_token) {
|
||||
throw Error("No user token provided.");
|
||||
}
|
||||
|
||||
return api_promise(
|
||||
json_parse(
|
||||
await (
|
||||
await fetch(`${host}/api/v1/${api_path}`, {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": content_type,
|
||||
"X-Cookie": `__Secure-atto-token=${user_token}`,
|
||||
},
|
||||
body:
|
||||
content_type === "application/json"
|
||||
? json_stringify(body)
|
||||
: body,
|
||||
})
|
||||
).text(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ...
|
||||
return {
|
||||
// app data
|
||||
app,
|
||||
query,
|
||||
insert,
|
||||
remove,
|
||||
remove_query,
|
||||
// user connection
|
||||
GRANT_URL,
|
||||
extract_verifier_token_uid,
|
||||
refresh_token,
|
||||
localstorage_accept_connection,
|
||||
request,
|
||||
};
|
||||
}
|
||||
|
||||
export function from_localstorage({
|
||||
host = "https://tetratto.com",
|
||||
app_id = 0n,
|
||||
}) {
|
||||
const user_verifier = window.localStorage.getItem("atto:grant.verifier");
|
||||
const user_token = window.localStorage.getItem("atto:grant.token");
|
||||
const user_id = window.localStorage.getItem("atto:grant.user_id");
|
||||
|
||||
return tetratto({
|
||||
host,
|
||||
app_id,
|
||||
user_verifier,
|
||||
user_id,
|
||||
user_token,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue