Web helpers
These are building blocks for signing in to services, receiving callbacks and talking to other apps. Nari doesn’t sign in for you: combine them the way the service needs.
A local web server
Section titled “A local web server”local server = nari.serve(function(request) -- request: { method, path, query, headers, body } if request.path == "/callback" then finish_login(request.query.code) return "<h1>You can go back to Nari</h1>" end return { status = 404, body = "Not here" }end)nari.log(server.url) -- http://127.0.0.1:<a free port>-- server.stop() when you're done- It only listens on
127.0.0.1, so only this device reaches it. - It picks a free port. Pass
{ port = 8898 }when the service only accepts a fixed address; it raises an error if that port is taken. - The handler returns a string (sent as HTML), a table
{ status, headers, body }, or nothing (204). If it fails, the browser gets a500. - Servers stop when their thread stops or the plugin is turned off.
Ciphers
Section titled “Ciphers”local cipher = nari.cipher({ algorithm = "aes-ctr", key = key, iv = iv })local plain = cipher:update(encrypted)| Key | |
|---|---|
algorithm |
aes-ctr, aes-cbc, aes-ecb (16, 24 or 32 byte keys), blowfish-cbc or blowfish-ecb (4 to 56 byte keys). |
key, iv |
Bytes. iv is the starting counter for CTR, and ECB doesn’t use it. |
decrypt |
true by default, false encrypts. CTR does both the same way. |
cipher:update(bytes) returns the processed bytes and carries on from where it stopped every time. CBC and ECB take
whole blocks (16 bytes for AES, 8 for Blowfish) and don’t add or remove padding. cipher:seek(offset) jumps a CTR
cipher to a byte offset, and cipher:reset() starts over. The work runs in Rust, fast enough for audio streams.
Links into Nari
Section titled “Links into Nari”nari://plugin/<your plugin id>/anything?you=want opens Nari (or the Nari that’s already open) and fires your
plugin’s link event with the whole URL. Services that only redirect to custom schemes can
send users back this way.
It works on Android and on Linux (the Flatpak registers the scheme). On Windows and macOS the link works when Nari is started with it.
Example: OAuth with PKCE
Section titled “Example: OAuth with PKCE”local verifier = nari.base64_encode(nari.random_bytes(32), true)local challenge = nari.base64_encode(nari.sha256(verifier, true), true)local state = nari.base64_encode(nari.random_bytes(16), true)
local serverserver = nari.serve(function(request) if request.path ~= "/callback" or request.query.state ~= state then return { status = 400, body = "Unexpected request" } end server.stop() nari.http({ method = "POST", url = "https://accounts.example.com/token", headers = { ["Content-Type"] = "application/x-www-form-urlencoded" }, body = "grant_type=authorization_code&code=" .. request.query.code .. "&code_verifier=" .. verifier .. "&redirect_uri=" .. server.url .. "/callback&client_id=MY_ID", }, function(response) nari.set("token", nari.json_decode(response.body).access_token, { private = true }) end) return "<h1>Signed in, you can close this tab</h1>"end)
nari.open_url("https://accounts.example.com/authorize?response_type=code&client_id=MY_ID" .. "&redirect_uri=" .. server.url .. "/callback&code_challenge_method=S256" .. "&code_challenge=" .. challenge .. "&state=" .. state)For sign-in pages that need cookies instead, use a web view.