<!DOCTYPE html>
<html>
-<head>
- <title>EstoulsAPI</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-</head>
-<body>
-<script>
-
-var EstoulsAPI =
-{
- username: undefined,
- apikey: undefined,
- endpoint: undefined,
-
- Math32:
- {
- clamp: a =>
- {
- while (a < 0 || a > 0xFFFFFFFF)
- a += a < 0 ? 0x100000000 : -0x100000000;
- return a;
- },
- shl: (a, b) => EstoulsAPI.Math32.clamp(a << b),
- shr: (a, b) => EstoulsAPI.Math32.clamp(a >>> b),
- rtl: (a, b) => EstoulsAPI.Math32.clamp((a << b) | (a >>> (32 - b))),
- rtr: (a, b) => EstoulsAPI.Math32.clamp((a >>> b) | (a << (32 - b))),
- add: (a, b) => EstoulsAPI.Math32.clamp(a + b),
- sub: (a, b) => EstoulsAPI.Math32.clamp(a + b),
- or: (a, b) => EstoulsAPI.Math32.clamp(a | b),
- xor: (a, b) => EstoulsAPI.Math32.clamp(a ^ b)
- },
- HMACSHA256:
- {
- sign: async (key, msg) =>
- {
- key = new Uint8Array(key);
- msg = new Uint8Array(msg);
- var ikey = await crypto.subtle.importKey
- (
- "raw",
- key,
- { name: "HMAC", hash: { name: "SHA-256" }},
- false,
- ["sign", "verify"]
- );
- return new Uint8Array(await window.crypto.subtle.sign({ name: "HMAC", }, ikey, msg));
- }
- },
- ChaCha20:
- {
- QR: (cc, a, b, c, d) =>
- {
- cc[a] = EstoulsAPI.Math32.add(cc[a], cc[b]);
- cc[d] = EstoulsAPI.Math32.xor(cc[d], cc[a]);
- cc[d] = EstoulsAPI.Math32.rtl(cc[d], 16);
-
- cc[c] = EstoulsAPI.Math32.add(cc[c], cc[d]);
- cc[b] = EstoulsAPI.Math32.xor(cc[b], cc[c]);
- cc[b] = EstoulsAPI.Math32.rtl(cc[b], 12);
-
- cc[a] = EstoulsAPI.Math32.add(cc[a], cc[b]);
- cc[d] = EstoulsAPI.Math32.xor(cc[d], cc[a]);
- cc[d] = EstoulsAPI.Math32.rtl(cc[d], 8);
-
- cc[c] = EstoulsAPI.Math32.add(cc[c], cc[d]);
- cc[b] = EstoulsAPI.Math32.xor(cc[b], cc[c]);
- cc[b] = EstoulsAPI.Math32.rtl(cc[b], 7);
- },
- DR: (cc) =>
- {
- EstoulsAPI.ChaCha20.QR(cc, 0, 4, 8, 12);
- EstoulsAPI.ChaCha20.QR(cc, 1, 5, 9, 13);
- EstoulsAPI.ChaCha20.QR(cc, 2, 6, 10, 14);
- EstoulsAPI.ChaCha20.QR(cc, 3, 7, 11, 15);
- EstoulsAPI.ChaCha20.QR(cc, 0, 5, 10, 15);
- EstoulsAPI.ChaCha20.QR(cc, 1, 6, 11, 12);
- EstoulsAPI.ChaCha20.QR(cc, 2, 7, 8, 13);
- EstoulsAPI.ChaCha20.QR(cc, 3, 4, 9, 14);
- },
- CB: (cc) =>
- {
- var i;
- var x = new Array(16);
- for (i = 0; i < 16; i++)
- {
- x[i] = cc[i];
- }
- for (i = 0; i < 10; i++)
- {
- EstoulsAPI.ChaCha20.DR(cc);
- }
- for (i = 0; i < 16; i++)
- {
- cc[i] = EstoulsAPI.Math32.add(cc[i], x[i]);
- }
- },
- S: (cc, cs) =>
- {
- for (var i = 0; i < 16; i++)
- {
- cs[4 * i] = (cc[i] & 0xFF);
- cs[4 * i + 1] = ((cc[i] >> 8) & 0xFF);
- cs[4 * i + 2] = ((cc[i] >> 16) & 0xFF);
- cs[4 * i + 3] = ((cc[i] >> 24) & 0xFF);
- }
- },
- B: (key, nonce, block, out) =>
- {
- var cc =
- [
- 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
-
- key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24),
- key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24),
- key[8] | (key[9] << 8) | (key[10] << 16) | (key[11] << 24),
- key[12] | (key[13] << 8) | (key[14] << 16) | (key[15] << 24),
-
- key[16] | (key[17] << 8) | (key[18] << 16) | (key[19] << 24),
- key[20] | (key[21] << 8) | (key[22] << 16) | (key[23] << 24),
- key[24] | (key[25] << 8) | (key[26] << 16) | (key[27] << 24),
- key[28] | (key[29] << 8) | (key[30] << 16) | (key[31] << 24),
-
- block,
-
- nonce[0] | (nonce[1] << 8) | (nonce[2] << 16) | (nonce[3] << 24),
- nonce[4] | (nonce[5] << 8) | (nonce[6] << 16) | (nonce[7] << 24),
- nonce[8] | (nonce[9] << 8) | (nonce[10] << 16) | (nonce[11] << 24)
- ];
-
- EstoulsAPI.ChaCha20.CB(cc);
- EstoulsAPI.ChaCha20.S(cc, out);
- },
- encrypt: async (key, nonce, block, data) =>
- {
- var count = data.length;
- if (count > (274877906944 - block * 64)) return null;
- var ret = new Array(0);
- var ccblock = new Array(64);
- var size = 0;
- while (count > 64)
- {
- ret.length = size + 64;
- EstoulsAPI.ChaCha20.B(key, nonce, block++, ccblock);
- for (var i = 0; i < 64; i++) ret[size + i] = ccblock[i];
- size += 64;
- count -= 64;
- }
- if (count > 0)
- {
- ret.length = size + count;
- EstoulsAPI.ChaCha20.B(key, nonce, block, ccblock);
- for (var i = 0; i < count; i++) ret[size + i] = ccblock[i];
- }
- for (var i = 0; i < data.length; i++) ret[i] ^= data[i];
- return new Uint8Array(ret);
- }
- },
-
- Base64:
- {
- encode: async (x) =>
- {
- return await new Promise(r =>
- {
- const reader = new FileReader();
- reader.addEventListener("load", () => r(reader.result.split(",")[1]));
- reader.readAsDataURL(new Blob([new Uint8Array(x)]));
- });
- },
-
- decode: (b64) =>
- {
- var dec1 = (v) =>
- {
- switch (v)
- {
- case 'A': return 0;
- case 'B': return 1;
- case 'C': return 2;
- case 'D': return 3;
- case 'E': return 4;
- case 'F': return 5;
- case 'G': return 6;
- case 'H': return 7;
- case 'I': return 8;
- case 'J': return 9;
- case 'K': return 10;
- case 'L': return 11;
- case 'M': return 12;
- case 'N': return 13;
- case 'O': return 14;
- case 'P': return 15;
- case 'Q': return 16;
- case 'R': return 17;
- case 'S': return 18;
- case 'T': return 19;
- case 'U': return 20;
- case 'V': return 21;
- case 'W': return 22;
- case 'X': return 23;
- case 'Y': return 24;
- case 'Z': return 25;
- case 'a': return 26;
- case 'b': return 27;
- case 'c': return 28;
- case 'd': return 29;
- case 'e': return 30;
- case 'f': return 31;
- case 'g': return 32;
- case 'h': return 33;
- case 'i': return 34;
- case 'j': return 35;
- case 'k': return 36;
- case 'l': return 37;
- case 'm': return 38;
- case 'n': return 39;
- case 'o': return 40;
- case 'p': return 41;
- case 'q': return 42;
- case 'r': return 43;
- case 's': return 44;
- case 't': return 45;
- case 'u': return 46;
- case 'v': return 47;
- case 'w': return 48;
- case 'x': return 49;
- case 'y': return 50;
- case 'z': return 51;
- case '0': return 52;
- case '1': return 53;
- case '2': return 54;
- case '3': return 55;
- case '4': return 56;
- case '5': return 57;
- case '6': return 58;
- case '7': return 59;
- case '8': return 60;
- case '9': return 61;
- case '+': return 62;
- case '/': return 63;
- }
- return 255;
- };
-
- var ret = new Array(0);
- var buffer = 0;
- var bufferS = 0;
- for (var i = 0; i < b64.length; i++)
- {
- if (b64[i] == '=') { bufferS = 0; continue; };
- var val = dec1(b64[i]);
- if (val == 255) return null;
- buffer = ((buffer << 6) | val) & 0xFFFF;
- bufferS += 6;
- if (bufferS >= 8)
+ <head>
+ <title>RosadoAPI</title>
+ <script type="text/javascript" src="rosado-api.js"></script>
+ <style type="text/css">
+ .tdlabel { width: 10%; text-align: center; }
+ .tdfield { width: 85%; text-align: center; }
+ .tdfield input, button, textarea { width: 100%; }
+ </style>
+ </head>
+ <body>
+ <h1><img src="favicon.ico" / width=48 height=48> RosadoAPI</h3>
+ <table style="width: 100%;">
+ <tr>
+ <td class="tdlabel">Address:</td>
+ <td class="tdfield"><input id="addr" type="text" /></td>
+ </tr>
+ <tr>
+ <td class="tdlabel">Service:</td>
+ <td class="tdfield"><input id="srvc" type="text" /></td>
+ </tr>
+ <tr>
+ <td class="tdlabel">Username:</td>
+ <td class="tdfield"><input id="user" type="text" /></td>
+ </tr>
+ <tr>
+ <td class="tdlabel">Authkey:</td>
+ <td class="tdfield"><input id="auth" type="text" /></td>
+ </tr>
+ <tr>
+ <td class="tdlabel">Request:</td>
+ <td class="tdfield"><textarea id="rqst" rows="8"></textarea></td>
+ </tr>
+ <tr>
+ <td class="tdlabel">Response:</td>
+ <td class="tdfield"><textarea id="resp" rows="8" disabled></textarea></td>
+ </tr>
+ <tr>
+ <td class="tdlabel"></td>
+ <td class="tdfield"><button type="button">Send</button></td>
+ </tr>
+ </table>
+ <script type="text/javascript">
+ $ = x => document.querySelector(x);
+ $("button").addEventListener("click", e =>
+ {
+ var addr = $("#addr").value;
+ var srvc = $("#srvc").value;
+ var user = $("#user").value;
+ var auth = $("#auth").value;
+ var rqst = $("#rqst").value;
+
+ localStorage.setItem("addr", addr);
+ localStorage.setItem("srvc", srvc);
+ localStorage.setItem("user", user);
+ localStorage.setItem("auth", auth);
+ localStorage.setItem("rqst", rqst);
+
+ RosadoAPI.username = user;
+ RosadoAPI.apikey = auth;
+ RosadoAPI.endpoint = addr + "/" + srvc;
+ RosadoAPI.request(rqst).then(x =>
{
- var shift = (16 - bufferS) & 0xFF;
- buffer = (buffer << shift) & 0xFFFF;
- ret[ret.length] = (buffer >>> 8) & 0xFF;
- buffer = buffer & 0x00FF;
- buffer = (buffer >>> shift) & 0xFFFF;
- bufferS -= 8;
- }
- }
- if (bufferS > 0)
- {
- buffer = (buffer << (16 - bufferS)) & 0xFFFF;
- ret[ret.length] = (buffer >>> 8) & 0xFF;
- }
- return new Uint8Array(ret);
- }
- },
-
- Hex:
- {
- encode: (x) =>
- {
- var ret = "";
- x.forEach(y => { ret += y.toString(16).padStart(2, "0"); });
- return ret;
- },
- decode: (x) =>
- {
- var arr = new Array(0);
- for (var i = 0; i < x.length; i += 2)
- {
- arr[arr.length] = parseInt(x.charAt(i) + x.charAt(i + 1), 16);
- }
- return new Uint8Array(arr);
- }
- },
-
- generateRequest: async (msg) =>
- {
- msg = new TextEncoder().encode(msg);
- var key = EstoulsAPI.Hex.decode(EstoulsAPI.apikey);
- //var sess = crypto.getRandomValues(new Uint8Array(12));
- var sess = new Uint8Array([0xba, 0x1f, 0x34, 0xdf, 0xf1, 0xb1, 0xd1, 0xce, 0xfb, 0x72, 0x28, 0x2b]);
- var rawdata = await EstoulsAPI.ChaCha20.encrypt(key, sess, 0, msg);
- var dgst = await EstoulsAPI.Hex.encode(await EstoulsAPI.HMACSHA256.sign(key, rawdata));
- var data = await EstoulsAPI.Base64.encode(rawdata);
- var resp = "user=" + EstoulsAPI.username;
- resp += "&sess=" + EstoulsAPI.Hex.encode(sess);
- resp += "&dgst=" + dgst;
- resp += "&data=" + data;
- return resp;
- },
-
- parseResponse: async (msg) =>
- {
- if (!msg.includes("user=") || !msg.includes("&sess=") || !msg.includes("&dgst=") || !msg.includes("&data="))
- {
- return { success: false, response: "invalid response" };
- }
- var user = msg.split("user=")[1].split("&")[0].trim();
- var sess = msg.split("&sess=")[1].split("&")[0].trim();
- var dgst = msg.split("&dgst=")[1].split("&")[0].trim();
- var data = msg.split("&data=")[1].split("&")[0].trim();
-
- if (user != EstoulsAPI.username)
- {
- return { success: false, response: "invalid user in response" };
- }
- data = EstoulsAPI.Base64.decode(data);
- sess = EstoulsAPI.Hex.decode(sess);
- var key = EstoulsAPI.Hex.decode(EstoulsAPI.apikey);
- var sig = await EstoulsAPI.Hex.encode(await EstoulsAPI.HMACSHA256.sign(key, data));
- if (sig != dgst)
- {
- return { success: false, response: "invalid signature" };
- }
- var resp = await EstoulsAPI.ChaCha20.encrypt(key, sess, 0, data);
- return { success: true, response: new TextDecoder().decode(resp) };
- },
-
- request: async (msg) =>
- {
- if (msg.trim().length == 0) return { success: true, response: "" };
- var req = await EstoulsAPI.generateRequest(msg);
- return await new Promise(r =>
- {
- const xhr = new XMLHttpRequest();
- xhr.open("POST", EstoulsAPI.endpoint, true);
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- xhr.onreadystatechange = (x) =>
- {
- if (xhr.readyState === XMLHttpRequest.DONE)
- {
- if (xhr.status === 200)
- {
- EstoulsAPI.parseResponse(xhr.responseText).then(pr => { r(pr); }).catch(x => alert("ERR(3)"));
- }
- else
- {
- r({success: false, response: xhr.status});
- }
- }
- }
- xhr.send(req);
- }).catch(x => alert("ERR(1): " + x));
- }
-
-};
-</script>
-
-
-
-<style>
-body { background-color: #1f1f1f; }
-table { background-color: #1f1f1f; }
-.basis
-{
- font-size: 14px;
- position: absolute;
- font-family: monospace;
- color: rgba(255, 255, 255, 0.5);
- width: 100%;
- background-color: rgba(0, 0, 0, 0);
- overflow-y: auto;
- outline: none;
- white-space: nowrap;
-}
-.overlay
-{
- font-size: 14px;
- pointer-events: none;
- font-family: monospace;
- width: 100%;
- background-color: #1f1f1f;
- color: #9cdcfe;
- font-weight: bold;
- overflow-y: auto;
- outline: none;
- white-space: nowrap;
-}
-.linecounter
-{
- font-size: 14px;
- width: 100%;
- text-align: center;
- font-weight: bold;
- font-family: monospace;
- background-color: #1f1f1f;
- color: #6e7681;
- overflow-y: auto;
- &::-webkit-scrollbar { display: none; }
- -ms-overflow-style: none;
- scrollbar-width: none;
-}
-
-.bracket { color: #da70d6; }
-.number { color: #b5cea8; }
-.comment { color: #6a9955; }
-.keyword { color: #dcdcaa; }
-.semicolon { color: #ffffff; }
-
-table { width: 100%; }
-
-.response
-{
- color: red;
- font-weight: bold;
- font-family: monospace;
-}
-
-.optionspanel
-{
- text-align: right;
- width: 100%;
-}
-.option
-{
- font-size: 24px;
- font-weight: bold;
- font-family: monospace;
- cursor: pointer;
- background-color: rgba(0,0,0,0);
- padding: 0;
- margin: 0;
- border: 0;
- display: inline-block;
-}
-#run { color: green; }
-#setup { font-size: 28px; color: grey; }
-#save,#help { font-size: 20px; display: none; }
-#load,#copy,#clear,#apk { font-size: 20px; }
-#apkwrapper { display: none; }
-
-</style>
-
-<div id="horizontal">
-
-<div class="optionspanel">
- <button class="option" id="load">📂</button>
- <button class="option" id="copy">📋</button>
- <button class="option" id="clear">🧹</button>
- <button class="option" id="save">💾</button><!-- -->
- <button class="option" id="run">▶</button><!-- -->
- <button class="option" id="help">❓</button>
- <div id="apkwrapper"><button class="option" id="apk">📲</button> </div>
- <button class="option" id="setup">⚙</button>
-</div>
-<table border="0">
- <tr>
- <td style="width: 3%;"><div class="linecounter">1</div></td>
- <td style="width: 96%; text-align: top;">
- <div class="basis" contenteditable spellcheck="false" autocorrect="off" autocapitalization="off"></div>
- <div class="overlay"></div>
- </td>
- </tr>
- <!-- <div>qreg q[2];</div><div>h q[0];</div><div>cx q[0], q[1];</div><div>sample;</div> -->
-</table>
-<hr style='border-color: #6e7681;' />
-<div class="response"></div>
-</div>
-
-<script>
-window.$ = x => document.querySelectorAll(x);
-var escapables =
-[
- [ "&", "&" ],
- [ " ", " " ],
- [ ">", ">" ],
- [ "<", "<" ],
-];
-
-function htmlToText(x, y)
-{
- var str;
- if (y == undefined)
- {
- var div = document.createElement("div");
- div.innerHTML = x;
- str = htmlToText(x, div);
- if (str.length > 0)
- {
- str = str.substring(0, str.length - 1);
- }
- return str;
- }
-
- if (y.nodeType == Node.TEXT_NODE)
- {
- return y.textContent + "\n";
- }
-
- str = "";
- if (y.tagName == "BR")
- {
- var prev = y.previousSibling;
- var next = y.nextSibling;
- window.brb = y;
-
- str = "\n";
- /*if (prev == null && next == null)
- {
- str = "\n";
- }
- else if (prev != null && prev.nodeType != Node.TEXT_NODE)
- {
- str = "\n";
- }
- else if (next != null && next.nodeType != Node.TEXT_NODE)
- {
- str = "\n";
- }*/
- if (next != null && next.tagName == "DIV")
- {
- str = "";
- if (prev == null)
- {
- str = "\n";
- }
- }
- }
-
- for (var i = 0; i < y.childNodes.length; i++)
- {
- str += htmlToText(x, y.childNodes[i]);
- }
- return str;
-}
-
-function removeEmptyNodes(v)
-{
- if (window.pauseCleaning) return;
- if (v == undefined)
- {
- removeEmptyNodes($(".basis")[0]);
- return;
- }
- /*
- if (v.tagName == "SPAN" && v.childNodes.length > 0)
- {
- v.parentNode.insertBefore(v.childNodes[0], v);
- v.remove();
- return;
- }
- */;
- if (v.tagName != "DIV")
- {
- return;
- }
- if (v.className != "basis")
- {
- if (v.innerHTML.length == 0)
- {
- v.remove();
- return;
- }
- }
- for (var i = 0; i < v.childNodes.length; i++)
- {
- removeEmptyNodes(v.childNodes[i]);
- }
-}
-
-function getText(x, y, z)
-{
- if (x == undefined || y == undefined)
- {
- z = [];
- getText([], $(".basis")[0], z);
- if (z.length == 0) return "";
- z.sort((a, b) => a[0] - b[0]);
- while (z.length > 0 && z[0][0] == 0)
- {
- z.splice(0, 1);
- }
- if (z.length == 0) return "";
- var str = "";
- var prevline = z[0][0];
- for (var i = 0; i < z.length; i++)
- {
- if (Math.abs(prevline - z[i][0]) > 5)
- {
- str += "\n";
- }
- str += z[i][1];
- prevline = z[i][0];
- }
- return str.replaceAll(String.fromCharCode(160), " ");
- }
-
- if (y.nodeType == Node.TEXT_NODE)
- {
- var r = document.createRange();
- r.selectNodeContents(y);
- var n = parseFloat(r.getBoundingClientRect().y.toString());
- n += parseFloat($(".basis")[0].scrollTop.toString());
- z[z.length] = [ r.getBoundingClientRect().y + $(".basis")[0].scrollTop, y.textContent ];
- return;
- }
- else if (y.className != "basis")
- {
- var n = parseFloat(y.getBoundingClientRect().y.toString());
- n += parseFloat($(".basis")[0].scrollTop.toString());
- z[z.length] = [ y.getBoundingClientRect().y + $(".basis")[0].scrollTop, "" ];
- }
-
- for (var i = 0; i < y.childNodes.length; i++)
- {
- getText(x, y.childNodes[i], z);
- }
-}
-
-function textToNodes(txt)
-{
- escapables.forEach(x => { txt = txt.replaceAll(x[1], x[0]); });
- var out = [];
- txt = txt.replaceAll("\r", "").replaceAll(" ", " ").split("\n");
- for (var i = 0; i < txt.length; i++)
- {
- var tmp = txt[i].trim();
- if (i == 0)
- {
- if (tmp.length > 0)
- {
- escapables.forEach(x => tmp = tmp.replaceAll(x[0], x[1]));
- out[out.length] = document.createTextNode(tmp);
- }
- }
- else
- {
- out[out.length] = document.createElement("div");
- if (tmp.length == 0)
- {
- out[out.length - 1].innerHTML = "<br>";
- }
- else
- {
- out[out.length - 1].innerHTML = tmp;
- }
- }
- }
- return out;
-}
-
-function setText(txt)
-{
- escapables.forEach(x => { txt = txt.replaceAll(x[1], x[0]); });
- var out = "";
- txt = txt.trim().replaceAll("\r", "").split("\n");
- for (var i = 0; i < txt.length; i++)
- {
- var tmp = txt[i].trim();
- if (tmp.length == 0)
- {
- out += "<div><br></div>";
- }
- else
- {
- out += "<div>" + tmp + "</div>";
- }
- }
- out = out.replaceAll(" ", " ");
- $(".basis")[0].innerHTML = out;
-}
-
-function highlightForQAnsel(txt)
-{
- var lhs = "!!!" + Math.random().toString().replace(".", "0") + "!!!";
- var rhs = "!!!" + Math.random().toString().replace(".", "1") + "!!!";
- txt = txt.replaceAll(/[&].*?[;]/g, x => lhs + x.replace("&", "").replace(";", "") + rhs);
- txt = txt.replaceAll(/[;]/g, "<span class='semicolon'>;</span>");
- txt = txt.replaceAll(new RegExp(lhs + ".*?" + rhs, "g"), x => "&" + x.replace(lhs, "").replace(rhs, "") + ";");
-
- txt = txt.replaceAll
- (
- /[\[][0-9][0-9]*[\]]/g,
- x =>
- {
- x = x.replace("[", "<span class='bracket'>[</span><span class='number'>");
- x = x.replace("]", "</span><span class='bracket'>]</span>");
- return x;
- }
- );
- //u(#,#,#); rx(#); ry(#); rz(#); if(c==#); if(c[#]==%i)
- var keywords =
- [
- "qreg",
- "creg",
- "density",
- "h",
- "x",
- "y",
- "z",
- "t",
- "s",
- "cx",
- "swap",
- "cswap",
- "fredkin",
- "ccx",
- "toffoli",
- "measure",
- "print",
- "sample",
- "reset",
- "barrier",
- "hvar",
- "rand",
- "born"
- ];
-
- for (var i = 0; i < keywords.length; i++)
- {
- var tmp = new RegExp("(^|[ ]|[;]|[>])" + keywords[i] + "($|[ ]|[<]|[&])", "g");
- txt = txt.replaceAll(tmp, x =>
- {
- var c = x.charAt(0);
- var tagonL = "";
- if (c == " " || c == ";" || c == ">")
- {
- tagonL = c;
- x = x.substring(1, x.length);
- }
- var tagonR = "";
- c = x.charAt(x.length - 1);
- if (c == " " || c == "<" || c == "&")
- {
- tagonR = c;
- x = x.substring(0, x.length - 1);
- }
- return tagonL + "<span class='keyword'>" + x + "</span>" + tagonR;
- });
- }
- txt = txt.replaceAll
- (
- /[/][/].*?([<]div|[<]br|$)/g,
- x =>
- {
- var tagon = "";
- var tagons = [ "<div", "<br" ];
- for (var i = 0; i < tagons.length; i++)
- {
- if (x.substring(x.length - tagons[i].length, x.length) == tagons[i])
- {
- x = x.substring(0, x.length - tagons[i].length);
- tagon = tagons[i];
- break;
- }
- }
- x = x.replaceAll(/[<]span[ ]class[=]['].*?['][>]/g, "<span>");
- x = "<span class='comment'>" + x + "</span>" + tagon;
- return x;
- }
- );
- return txt;
-}
-
-if (window.location.hash == "#mobile")
-{
- $("#horizontal")[0].remove();
- var iframe = document.createElement("iframe");
- iframe.src = window.location.href.split("#")[0];
- iframe.style.width = window.innerHeight + "px";
- iframe.style.height = window.innerWidth + "px";
- iframe.style.transformOrigin = "top left";
- iframe.style.transform = "rotate(90deg)";
- iframe.style.position = "fixed";
- iframe.style.top = "0px";
- iframe.style.left = window.innerWidth + "px";
- iframe.frameBorder = "0";
- document.body.appendChild(iframe);
-
-}
-else
-{
- window.addEventListener("DOMContentLoaded", () =>
- {
- if (window.location.href.includes(".com") || window.location.href.includes("192."))
- {
- $("#apkwrapper")[0].style.display = "inline-block";
- }
- setTimeout(function()
- {
- try
- {
- var tmp = Math.round($(".overlay")[0].getBoundingClientRect().width) + "px";
- $(".overlay")[0].style.width = tmp;
- $(".basis")[0].style.width = tmp;
- $(".basis,.overlay,.linecounter").forEach(x =>
- {
- x.style.height = (window.innerHeight * 0.40) + "px";
- });
- $(".response")[0].style.height = (window.innerHeight * 0.40) + "px";
-
- var prevText = localStorage.getItem("previous_text");
- if (prevText)
- {
- if (typeof(prevText) == "string")
+ if (x.success && x.response.trim().length > 0)
+ {
+ $("#resp").style.color = "green";
+ $("#resp").value = x.response;
+ }
+ else if (x.response.trim().length == 0)
{
- setText(prevText);
+ $("#resp").style.color = "brown";
+ $("#resp").value = "Empty response.";
+ }
+ else
+ {
+ $("#resp").style.color = "red";
+ $("#resp").value = x.response;
}
- }
- }
- catch (x)
- {
- alert("ERR(4): " + x);
- }
- }, 100);
-
- //$(".basis")[0].style.top = Math.round($(".overlay")[0].getBoundingClientRect().top) + "px";
- //$(".basis")[0].style.left = Math.round($(".overlay")[0].getBoundingClientRect().left) + "px";
- });
-
- $("#clear")[0].addEventListener("click", () =>
- {
- setText("");
- });
-
- $("#apk")[0].addEventListener("click", () =>
- {
- var a = document.createElement("a");
- a.href = "/apk";
- a.download = "EstoulsAPI.apk";
- a.style.display = "none";
- document.body.appendChild(a);
- a.click();
- a.remove();
- });
-
- $("#save")[0].addEventListener("click", () =>
- {
- var txt = btoa($(".basis")[0].innerText);
- txt = "data:text/plain;base64," + txt;
- var a = document.createElement("a");
- a.href = txt;
- a.download = "program.txt";
- a.style.display = "none";
- document.body.appendChild(a);
- a.click();
- a.remove();
- });
-
- $("#copy")[0].addEventListener("click", () =>
- {
- var tmp = document.createElement('textarea');
- tmp.value = getText();
- document.body.appendChild(tmp);
- tmp.focus();
- tmp.select();
- document.execCommand('copy');
- tmp.remove();
- });
-
-
- $("#help")[0].addEventListener("click", () =>
- {
- window.location.href = "https://doi.org/10.48550/arXiv.1707.03429";
- });
-
- $("#load")[0].addEventListener("click", () =>
- {
- var load = document.createElement("input");
- load.type = "file";
- load.style.display = "none";
- /*while ($("input[type=file]").length > 0)
- {
- $("input[type=file]")[0].remove();
- }*/
- window.pr = new Promise(r =>
- {
- load.addEventListener("change", () =>
- {
- var reader = new FileReader();
- reader.addEventListener("load", (e) =>
- {
- r(atob(e.target.result.split(",")[1]));
- load.remove();
});
- reader.readAsDataURL(load.files[0]);
});
- document.body.appendChild(load);
- load.click();
- }).then(text =>
- {
- var tmp = "!!!" + Math.random().toString().replace(".", "0") + "!!!";
- text = text.trim().replaceAll("\n", tmp).replaceAll("\r", "");
- tmp = text.replaceAll(tmp, "</div><div>");
- if (tmp.substring(0, 5) != "<div>")
- {
- tmp = "<div>" + tmp;
- }
- if (tmp.substring(tmp.length - 5, tmp.length) == "<div>")
- {
- tmp = tmp.substring(0, tmp.length - 5);
- }
- tmp = tmp.replaceAll("<div></div>", "<div><br></div>");
- $(".basis")[0].innerHTML = tmp;
- });
- });
-
- $("#setup")[0].addEventListener("click", () =>
- {
- var msg = "username:apikey:endpoint";
- var dat = localStorage.getItem("api_info");
- dat = dat == null ? prompt(msg) : prompt(msg, dat);
- if (dat == null) return;
- dat = dat.replace("http://", "").replace("https://", "");
- localStorage.setItem("api_info", dat);
- });
-
- $("#run")[0].addEventListener("click", () =>
- {
- var dat = localStorage.getItem("api_info");
- if (dat == null || dat == undefined)
- {
- $(".response")[0].style.color = "red";
- $(".response")[0].innerText = "API info not set.\nPlease press the gear on the top-right.";
- return;
- }
- dat = dat.split(":");
- if (dat.length != 3)
- {
- $(".response")[0].style.color = "red";
- $(".response")[0].innerText = "API info not set correctly.\nPlease press the gear on the top-right.";
- return;
- }
-
- EstoulsAPI.username = dat[0];
- EstoulsAPI.apikey = dat[1];
- EstoulsAPI.endpoint = "https://" + dat[2];
- EstoulsAPI.request(getText()).then(x =>
- {
- if (x.success && x.response.trim().length > 0)
- {
- $(".response")[0].style.color = "green";
- $(".response")[0].innerText = x.response;
- }
- else if (x.success && x.response.trim().length == 0)
- {
- $(".response")[0].style.color = "yellow";
- $(".response")[0].innerText = "Empty response.";
- }
- else
- {
- $(".response")[0].style.color = "red";
- $(".response")[0].innerText = x.response;
- }
- }).catch(x => alert("ERR(2)" + x));
- });
-
- $(".basis")[0].addEventListener("paste", (e) =>
- {
- window.pauseCleaning = true;
- e.preventDefault();
- var text = (event.clipboardData || window.clipboardData).getData('text');
- //text = htmlToText(text);
- var sel = window.getSelection();
- if (sel.rangeCount > 0)
- {
- var range = sel.getRangeAt(0);
- range.deleteContents();
- if (!text.includes("\n"))
- {
- var textNode = document.createTextNode(text);
- range.insertNode(textNode);
- range.setStartAfter(textNode);
- range.setEndAfter(textNode);
- sel.removeAllRanges();
- sel.addRange(range);
- }
- else
+ document.addEventListener("DOMContentLoaded", () =>
{
- var last;
- textToNodes(text).forEach(x =>
+ var has = x => localStorage.getItem(x) != null && localStorage.getItem(x) != "";
+ if (!has("addr")) localStorage.setItem("addr", window.location.origin);
+ for (var field of [ "addr", "srvc", "user", "auth", "rqst" ])
{
- range.insertNode(x);
- range.setStartAfter(x);
- range.setEndAfter(x);
- });
- sel.removeAllRanges();
- sel.addRange(range);
- }
- }
- window.pauseCleaning = undefined;
- });
-
- setInterval(() =>
- {
- if (window.stopMainLoop) return;
- try
- {
- removeEmptyNodes();
- $(".overlay")[0].scrollTop = $(".basis")[0].scrollTop;
- $(".overlay")[0].scrollLeft = $(".basis")[0].scrollLeft;
- $(".linecounter")[0].scrollTop = $(".basis")[0].scrollTop;
- $(".linecounter")[0].scrollTop = $(".basis")[0].scrollTop;
- var txt = $(".basis")[0].innerHTML;
- if (txt == window.oldHTML) return;
- localStorage.setItem("previous_text", getText());
-
- //<fix for a mobile bug>
- /*
- var pos = 0;
- var found = false;
- for (; pos < txt.length; pos++)
- {
- if (txt.substring(pos, pos + "<div>".length) == "<div>")
+ $("#" + field).value = has(field) ? localStorage.getItem(field) : "";
+ }
+ if (localStorage.getItem("addr") == null || localStorage.getItem("addr") == "")
{
- found = true;
- break;
+ localStorage.setItem("addr", window.location.origin);
}
- }
- if (pos != 0 && found)
- {
- var lhs = txt.substring(0, pos);
- var rhs = txt.substring(pos, txt.length);
- txt = "<div>" + lhs + "</div>" + rhs;
- $(".basis")[0].innerHTML = txt;
- }
- if (txt.includes("</div><br><div>"))
- {
- txt = txt.replaceAll("</div><br><div>", "");
- $(".basis")[0].innerHTML = txt;
-
- }*/
- //</fix for a mobile bug>
-
- if (txt.includes("qreg") || txt.includes("creg"))
- {
- txt = highlightForQAnsel(txt);
- }
-
- $(".overlay")[0].innerHTML = txt;
- window.oldHTML = $(".basis")[0].innerHTML;
- txt = $(".basis")[0].innerHTML;
- var linecount = getText().split("\n").length;
- txt = "";
- for (var i = 0; i < linecount; i++)
- {
- txt += (i + 1) + "<br />";
- }
- $(".linecounter")[0].innerHTML = txt;
- }
- catch (x)
- {
- alert("ERR(3): " + x);
- window.stopMainLoop = true;
- }
- }, 10);
-}
-</script>
-</body>
-</html>
+ $("#resp").value = "";
+ });
+ </script>
+ </body>
+</html>
--- /dev/null
+var RosadoAPI =
+{
+ username: undefined,
+ apikey: undefined,
+ endpoint: undefined,
+
+ Math32:
+ {
+ clamp: a =>
+ {
+ while (a < 0 || a > 0xFFFFFFFF)
+ a += a < 0 ? 0x100000000 : -0x100000000;
+ return a;
+ },
+ shl: (a, b) => RosadoAPI.Math32.clamp(a << b),
+ shr: (a, b) => RosadoAPI.Math32.clamp(a >>> b),
+ rtl: (a, b) => RosadoAPI.Math32.clamp((a << b) | (a >>> (32 - b))),
+ rtr: (a, b) => RosadoAPI.Math32.clamp((a >>> b) | (a << (32 - b))),
+ add: (a, b) => RosadoAPI.Math32.clamp(a + b),
+ sub: (a, b) => RosadoAPI.Math32.clamp(a + b),
+ or: (a, b) => RosadoAPI.Math32.clamp(a | b),
+ xor: (a, b) => RosadoAPI.Math32.clamp(a ^ b)
+ },
+ HMACSHA256:
+ {
+ sign: async (key, msg) =>
+ {
+ key = new Uint8Array(key);
+ msg = new Uint8Array(msg);
+ var ikey = await crypto.subtle.importKey
+ (
+ "raw",
+ key,
+ { name: "HMAC", hash: { name: "SHA-256" }},
+ false,
+ ["sign", "verify"]
+ );
+ return new Uint8Array(await window.crypto.subtle.sign({ name: "HMAC", }, ikey, msg));
+ }
+ },
+ ChaCha20:
+ {
+ QR: (cc, a, b, c, d) =>
+ {
+ cc[a] = RosadoAPI.Math32.add(cc[a], cc[b]);
+ cc[d] = RosadoAPI.Math32.xor(cc[d], cc[a]);
+ cc[d] = RosadoAPI.Math32.rtl(cc[d], 16);
+
+ cc[c] = RosadoAPI.Math32.add(cc[c], cc[d]);
+ cc[b] = RosadoAPI.Math32.xor(cc[b], cc[c]);
+ cc[b] = RosadoAPI.Math32.rtl(cc[b], 12);
+
+ cc[a] = RosadoAPI.Math32.add(cc[a], cc[b]);
+ cc[d] = RosadoAPI.Math32.xor(cc[d], cc[a]);
+ cc[d] = RosadoAPI.Math32.rtl(cc[d], 8);
+
+ cc[c] = RosadoAPI.Math32.add(cc[c], cc[d]);
+ cc[b] = RosadoAPI.Math32.xor(cc[b], cc[c]);
+ cc[b] = RosadoAPI.Math32.rtl(cc[b], 7);
+ },
+ DR: (cc) =>
+ {
+ RosadoAPI.ChaCha20.QR(cc, 0, 4, 8, 12);
+ RosadoAPI.ChaCha20.QR(cc, 1, 5, 9, 13);
+ RosadoAPI.ChaCha20.QR(cc, 2, 6, 10, 14);
+ RosadoAPI.ChaCha20.QR(cc, 3, 7, 11, 15);
+ RosadoAPI.ChaCha20.QR(cc, 0, 5, 10, 15);
+ RosadoAPI.ChaCha20.QR(cc, 1, 6, 11, 12);
+ RosadoAPI.ChaCha20.QR(cc, 2, 7, 8, 13);
+ RosadoAPI.ChaCha20.QR(cc, 3, 4, 9, 14);
+ },
+ CB: (cc) =>
+ {
+ var i;
+ var x = new Array(16);
+ for (i = 0; i < 16; i++)
+ {
+ x[i] = cc[i];
+ }
+ for (i = 0; i < 10; i++)
+ {
+ RosadoAPI.ChaCha20.DR(cc);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ cc[i] = RosadoAPI.Math32.add(cc[i], x[i]);
+ }
+ },
+ S: (cc, cs) =>
+ {
+ for (var i = 0; i < 16; i++)
+ {
+ cs[4 * i] = (cc[i] & 0xFF);
+ cs[4 * i + 1] = ((cc[i] >> 8) & 0xFF);
+ cs[4 * i + 2] = ((cc[i] >> 16) & 0xFF);
+ cs[4 * i + 3] = ((cc[i] >> 24) & 0xFF);
+ }
+ },
+ B: (key, nonce, block, out) =>
+ {
+ var cc =
+ [
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
+
+ key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24),
+ key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24),
+ key[8] | (key[9] << 8) | (key[10] << 16) | (key[11] << 24),
+ key[12] | (key[13] << 8) | (key[14] << 16) | (key[15] << 24),
+
+ key[16] | (key[17] << 8) | (key[18] << 16) | (key[19] << 24),
+ key[20] | (key[21] << 8) | (key[22] << 16) | (key[23] << 24),
+ key[24] | (key[25] << 8) | (key[26] << 16) | (key[27] << 24),
+ key[28] | (key[29] << 8) | (key[30] << 16) | (key[31] << 24),
+
+ block,
+
+ nonce[0] | (nonce[1] << 8) | (nonce[2] << 16) | (nonce[3] << 24),
+ nonce[4] | (nonce[5] << 8) | (nonce[6] << 16) | (nonce[7] << 24),
+ nonce[8] | (nonce[9] << 8) | (nonce[10] << 16) | (nonce[11] << 24)
+ ];
+
+ RosadoAPI.ChaCha20.CB(cc);
+ RosadoAPI.ChaCha20.S(cc, out);
+ },
+ encrypt: async (key, nonce, block, data) =>
+ {
+ var count = data.length;
+ if (count > (274877906944 - block * 64)) return null;
+ var ret = new Array(0);
+ var ccblock = new Array(64);
+ var size = 0;
+ while (count > 64)
+ {
+ ret.length = size + 64;
+ RosadoAPI.ChaCha20.B(key, nonce, block++, ccblock);
+ for (var i = 0; i < 64; i++) ret[size + i] = ccblock[i];
+ size += 64;
+ count -= 64;
+ }
+ if (count > 0)
+ {
+ ret.length = size + count;
+ RosadoAPI.ChaCha20.B(key, nonce, block, ccblock);
+ for (var i = 0; i < count; i++) ret[size + i] = ccblock[i];
+ }
+ for (var i = 0; i < data.length; i++) ret[i] ^= data[i];
+ return new Uint8Array(ret);
+ }
+ },
+
+ Base64:
+ {
+ encode: async (x) =>
+ {
+ return await new Promise(r =>
+ {
+ const reader = new FileReader();
+ reader.addEventListener("load", () => r(reader.result.split(",")[1]));
+ reader.readAsDataURL(new Blob([new Uint8Array(x)]));
+ });
+ },
+
+ decode: (b64) =>
+ {
+ var dec1 = (v) =>
+ {
+ switch (v)
+ {
+ case 'A': return 0;
+ case 'B': return 1;
+ case 'C': return 2;
+ case 'D': return 3;
+ case 'E': return 4;
+ case 'F': return 5;
+ case 'G': return 6;
+ case 'H': return 7;
+ case 'I': return 8;
+ case 'J': return 9;
+ case 'K': return 10;
+ case 'L': return 11;
+ case 'M': return 12;
+ case 'N': return 13;
+ case 'O': return 14;
+ case 'P': return 15;
+ case 'Q': return 16;
+ case 'R': return 17;
+ case 'S': return 18;
+ case 'T': return 19;
+ case 'U': return 20;
+ case 'V': return 21;
+ case 'W': return 22;
+ case 'X': return 23;
+ case 'Y': return 24;
+ case 'Z': return 25;
+ case 'a': return 26;
+ case 'b': return 27;
+ case 'c': return 28;
+ case 'd': return 29;
+ case 'e': return 30;
+ case 'f': return 31;
+ case 'g': return 32;
+ case 'h': return 33;
+ case 'i': return 34;
+ case 'j': return 35;
+ case 'k': return 36;
+ case 'l': return 37;
+ case 'm': return 38;
+ case 'n': return 39;
+ case 'o': return 40;
+ case 'p': return 41;
+ case 'q': return 42;
+ case 'r': return 43;
+ case 's': return 44;
+ case 't': return 45;
+ case 'u': return 46;
+ case 'v': return 47;
+ case 'w': return 48;
+ case 'x': return 49;
+ case 'y': return 50;
+ case 'z': return 51;
+ case '0': return 52;
+ case '1': return 53;
+ case '2': return 54;
+ case '3': return 55;
+ case '4': return 56;
+ case '5': return 57;
+ case '6': return 58;
+ case '7': return 59;
+ case '8': return 60;
+ case '9': return 61;
+ case '+': return 62;
+ case '/': return 63;
+ }
+ return 255;
+ };
+
+ var ret = new Array(0);
+ var buffer = 0;
+ var bufferS = 0;
+ for (var i = 0; i < b64.length; i++)
+ {
+ if (b64[i] == '=') { bufferS = 0; continue; };
+ var val = dec1(b64[i]);
+ if (val == 255) return null;
+ buffer = ((buffer << 6) | val) & 0xFFFF;
+ bufferS += 6;
+ if (bufferS >= 8)
+ {
+ var shift = (16 - bufferS) & 0xFF;
+ buffer = (buffer << shift) & 0xFFFF;
+ ret[ret.length] = (buffer >>> 8) & 0xFF;
+ buffer = buffer & 0x00FF;
+ buffer = (buffer >>> shift) & 0xFFFF;
+ bufferS -= 8;
+ }
+ }
+ if (bufferS > 0)
+ {
+ buffer = (buffer << (16 - bufferS)) & 0xFFFF;
+ ret[ret.length] = (buffer >>> 8) & 0xFF;
+ }
+ return new Uint8Array(ret);
+ }
+ },
+
+ Hex:
+ {
+ encode: (x) =>
+ {
+ var ret = "";
+ x.forEach(y => { ret += y.toString(16).padStart(2, "0"); });
+ return ret;
+ },
+ decode: (x) =>
+ {
+ var arr = new Array(0);
+ for (var i = 0; i < x.length; i += 2)
+ {
+ arr[arr.length] = parseInt(x.charAt(i) + x.charAt(i + 1), 16);
+ }
+ return new Uint8Array(arr);
+ }
+ },
+
+ generateRequest: async (msg) =>
+ {
+ msg = new TextEncoder().encode(msg);
+ var key = RosadoAPI.Hex.decode(RosadoAPI.apikey);
+ //var sess = crypto.getRandomValues(new Uint8Array(12));
+ var r = () => { return Math.floor(Math.random() * 10000) % 256 };;
+ var sess = new Uint8Array([r(), r(), r(), r(), r(), r(), r(), r(), r(), r(), r(), r()]);
+ var rawdata = await RosadoAPI.ChaCha20.encrypt(key, sess, 0, msg);
+ var dgst = await RosadoAPI.Hex.encode(await RosadoAPI.HMACSHA256.sign(key, rawdata));
+ var data = await RosadoAPI.Base64.encode(rawdata);
+ var resp = "user=" + RosadoAPI.username;
+ resp += "&sess=" + RosadoAPI.Hex.encode(sess);
+ resp += "&dgst=" + dgst;
+ resp += "&data=" + data;
+ return resp;
+ },
+
+ parseResponse: async (msg) =>
+ {
+ if (!msg.includes("user=") || !msg.includes("&sess=") || !msg.includes("&dgst=") || !msg.includes("&data="))
+ {
+ return { success: false, response: "invalid response" };
+ }
+ var user = msg.split("user=")[1].split("&")[0].trim();
+ var sess = msg.split("&sess=")[1].split("&")[0].trim();
+ var dgst = msg.split("&dgst=")[1].split("&")[0].trim();
+ var data = msg.split("&data=")[1].split("&")[0].trim();
+
+ if (user != RosadoAPI.username)
+ {
+ return { success: false, response: "invalid user in response" };
+ }
+ data = RosadoAPI.Base64.decode(data);
+ sess = RosadoAPI.Hex.decode(sess);
+ var key = RosadoAPI.Hex.decode(RosadoAPI.apikey);
+ var sig = await RosadoAPI.Hex.encode(await RosadoAPI.HMACSHA256.sign(key, data));
+ if (sig != dgst)
+ {
+ return { success: false, response: "invalid signature" };
+ }
+ var resp = await RosadoAPI.ChaCha20.encrypt(key, sess, 0, data);
+ resp = new TextDecoder().decode(resp);
+ resp = resp ? resp : "(null)";
+ return { success: true, response: resp };
+ },
+
+ request: async (msg) =>
+ {
+ if (msg.trim().length == 0) return { success: true, response: "" };
+ var req = await RosadoAPI.generateRequest(msg);
+ return await new Promise(r =>
+ {
+ const xhr = new XMLHttpRequest();
+ xhr.open("POST", RosadoAPI.endpoint, true);
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ xhr.onreadystatechange = (x) =>
+ {
+ if (xhr.readyState === XMLHttpRequest.DONE)
+ {
+ if (xhr.status === 200)
+ {
+ RosadoAPI.parseResponse(xhr.responseText).then(pr => { r(pr); }).catch(x => alert("ERR(3)"));
+ }
+ else
+ {
+ r({success: false, response: xhr.status.toString()});
+ }
+ }
+ }
+ xhr.send(req);
+ }).catch(x => alert("ERR(1): " + x));
+ }
+};
+