mirror of
https://github.com/Niko1221/Strata.git
synced 2026-11-07 06:15:58 -10:00
Web page: use an edited API key at once, even when browser storage is blocked (#3435)
Ported from #3435 by engharat. Co-authored-by: engharat <[email protected]>
This commit is contained in:
1 parent
0351ecb11d
commit
2ba95cf61f
2 files changed
+113
-5
No files matched your search
@@ -0,0 +1,99 @@
|
||||
"""The web app uses an edited API key immediately, even when site storage is blocked.
|
||||
|
||||
Runs the page's storage and server-access code with Node, without a GPU or server:
|
||||
python -m unittest serve.test_web_api_key -v
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
APP = Path(__file__).with_name("web") / "app.js"
|
||||
|
||||
|
||||
@unittest.skipUnless(shutil.which("node"), "node is not installed")
|
||||
class WebApiKey(unittest.TestCase):
|
||||
def run_js(self, actions, *, stored=None, blocked=False, quota=False):
|
||||
src = APP.read_text(encoding="utf-8")
|
||||
store = src[src.index("const store ="):src.index("// ------------------------------------------------------------------ toasts")]
|
||||
access = src[src.index("// ------------------------------------------------------------------ server access"):src.index("let health =")]
|
||||
js = f"""
|
||||
const data = new Map(Object.entries({json.dumps(stored or {})}));
|
||||
const field = {{value: ""}};
|
||||
const notices = [];
|
||||
const $ = () => field;
|
||||
const toast = (...args) => notices.push(args);
|
||||
const localStorage = {{
|
||||
getItem(k) {{
|
||||
if ({json.dumps(blocked)}) throw new Error("Storage blocked");
|
||||
return data.has(k) ? data.get(k) : null;
|
||||
}},
|
||||
setItem(k, v) {{
|
||||
if ({json.dumps(blocked or quota)}) throw new Error("Storage unavailable");
|
||||
data.set(k, v);
|
||||
}},
|
||||
}};
|
||||
function edit(value, event = "input") {{
|
||||
field.value = value;
|
||||
const handler = field["on" + event];
|
||||
if (handler) handler();
|
||||
}}
|
||||
{store}
|
||||
{access}
|
||||
{actions}
|
||||
"""
|
||||
result = subprocess.run(["node", "-e", js], capture_output=True, text=True, timeout=30)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
def test_input_is_used_and_saved_without_blur(self):
|
||||
got = self.run_js('''
|
||||
edit(" test-key ");
|
||||
console.log(JSON.stringify({headers: headers(true), saved: data.get("strata.apikey")}));
|
||||
''')
|
||||
self.assertEqual(got, {"headers": {"Authorization": "Bearer test-key", "Content-Type": "application/json"},
|
||||
"saved": '"test-key"'})
|
||||
|
||||
def test_saved_key_is_restored_on_reload(self):
|
||||
got = self.run_js('console.log(JSON.stringify({value: field.value, headers: headers()}));',
|
||||
stored={"strata.apikey": '"saved-key"'})
|
||||
self.assertEqual(got, {"value": "saved-key", "headers": {"Authorization": "Bearer saved-key"}})
|
||||
|
||||
def test_blocked_storage_still_uses_key_in_memory(self):
|
||||
got = self.run_js('edit("test-key", "change"); console.log(JSON.stringify(headers()));', blocked=True)
|
||||
self.assertEqual(got, {"Authorization": "Bearer test-key"})
|
||||
|
||||
def test_failed_write_does_not_reuse_old_key(self):
|
||||
got = self.run_js('edit("new-key", "change"); console.log(JSON.stringify(headers()));',
|
||||
stored={"strata.apikey": '"old-key"'}, quota=True)
|
||||
self.assertEqual(got, {"Authorization": "Bearer new-key"})
|
||||
|
||||
def test_clearing_key_removes_authorization(self):
|
||||
for quota in (False, True):
|
||||
with self.subTest(quota=quota):
|
||||
got = self.run_js('edit(" "); console.log(JSON.stringify(headers()));',
|
||||
stored={"strata.apikey": '"old-key"'}, quota=quota)
|
||||
self.assertEqual(got, {})
|
||||
|
||||
def test_successful_save_notifies_only_on_change(self):
|
||||
got = self.run_js('''
|
||||
edit("test-key");
|
||||
const before = notices.length;
|
||||
edit("test-key", "change");
|
||||
console.log(JSON.stringify({before, kinds: notices.map(n => n[0])}));
|
||||
''')
|
||||
self.assertEqual(got, {"before": 0, "kinds": ["success"]})
|
||||
|
||||
def test_failed_save_warns_instead_of_claiming_success(self):
|
||||
got = self.run_js('edit("test-key", "change"); console.log(JSON.stringify(notices.map(n => n[0])));',
|
||||
blocked=True)
|
||||
self.assertEqual(got, ["warn"])
|
||||
|
||||
def test_server_without_key_keeps_json_header_only(self):
|
||||
got = self.run_js('console.log(JSON.stringify(headers(true)));')
|
||||
self.assertEqual(got, {"Content-Type": "application/json"})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+14
-5
@@ -14,7 +14,7 @@ const gb = (b, d = 1) => (b == null ? "–" : fmt(b / 1073741824, d)); // memo
|
||||
|
||||
const store = {
|
||||
get(k, d) { try { const v = localStorage.getItem("strata." + k); return v === null ? d : JSON.parse(v); } catch (e) { return d; } },
|
||||
set(k, v) { try { localStorage.setItem("strata." + k, JSON.stringify(v)); } catch (e) { /* private mode: in memory only */ } },
|
||||
set(k, v) { try { localStorage.setItem("strata." + k, JSON.stringify(v)); return true; } catch (e) { return false; } },
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------ toasts
|
||||
@@ -87,15 +87,24 @@ for (const b of document.querySelectorAll(".st-tab")) b.onclick = () => showTab(
|
||||
window.addEventListener("hashchange", () => showTab(location.hash.slice(1)));
|
||||
|
||||
// ------------------------------------------------------------------ server access
|
||||
let apiKey = store.get("apikey", "");
|
||||
function headers(json = false) {
|
||||
const h = {};
|
||||
const key = store.get("apikey", "");
|
||||
if (key) h.Authorization = "Bearer " + key;
|
||||
if (apiKey) h.Authorization = "Bearer " + apiKey;
|
||||
if (json) h["Content-Type"] = "application/json";
|
||||
return h;
|
||||
}
|
||||
$("api-key").value = store.get("apikey", "");
|
||||
$("api-key").onchange = () => { store.set("apikey", $("api-key").value.trim()); toast("success", "API key saved", "Kept in this browser only."); };
|
||||
$("api-key").value = apiKey;
|
||||
function saveApiKey(notify = false) {
|
||||
apiKey = $("api-key").value.trim(); // usable even when browser storage is blocked or full
|
||||
const saved = store.set("apikey", apiKey);
|
||||
if (notify) {
|
||||
if (saved) toast("success", "API key saved", "Kept in this browser only.");
|
||||
else toast("warn", "API key used for this page only", "Browser storage is unavailable. Enter it again after reloading.");
|
||||
}
|
||||
}
|
||||
$("api-key").oninput = () => saveApiKey();
|
||||
$("api-key").onchange = () => saveApiKey(true);
|
||||
|
||||
let health = {model: "strata", images: false, max_context: 0};
|
||||
async function loadHealth() {
|
||||
|
||||
Reference in new issue
Block a user