soma.cell

Session/login toy: POST /login issues a token, GET /me/<token> returns the user, POST /logout invalidates it

Tokens map to usernames.

A Soma program from the web part of the verified corpus: 58 lines, cells Sessions, SessionsTest. It passes soma check with soma 3.2.4.

How it is built

The cell Sessions declares 4 signals in its face: request(method: String, path: String, body: String) -> Map, login(user: String, pass: String) -> Map, whoami(token: String) -> Map and logout(token: String) -> Map; keeps 1 memory slot: tokens (Map<String, String>, persistent and consistent). Handlers: login (line 17), whoami (line 24), logout (line 30) and request (line 35).

The file also holds 1 test cell (SessionsTest) with 4 assertions, run by soma test.

Generated from soma describe on this file.

The source

soma.toml

[package]
name = "web-corpus"
version = "0.1.0"
entry = "todo_state.cell"

[verify]
cells = ["TodoService"]
deadlock_free = true
eventually = ["Done", "Cancelled"]

sessions.cell

// Session/login toy: POST /login issues a token, GET /me/<token> returns
// the user, POST /logout invalidates it. Tokens map to usernames.

cell Sessions {
    face {
        signal request(method: String, path: String, body: String) -> Map
        signal login(user: String, pass: String) -> Map
        signal whoami(token: String) -> Map
        signal logout(token: String) -> Map
        promise all_persistent
    }

    memory {
        tokens: Map<String, String> [persistent, consistent]
    }

    on login(user: String, pass: String) {
        if pass != "secret" { return response(401, map("error", "bad credentials")) }
        let token = concat("tok-", concat(user, concat("-", to_string(next_id()))))
        tokens.set(token, user)
        return map("token", token, "user", user)
    }

    on whoami(token: String) {
        let user = tokens.get(token)
        if user == () { return response(401, map("error", "invalid token")) }
        return map("user", user)
    }

    on logout(token: String) {
        let existed = tokens.delete(token)
        return map("logged_out", existed)
    }

    on request(method: String, path: String, body: String) {
        let req = map("method", method, "path", path)
        match req {
            {method: "POST", path: "/login"}      -> {
                let d = from_json(body)
                login(d.user, d.pass)
            }
            {method: "GET",  path: "/me/" + tok}  -> whoami(tok)
            {method: "POST", path: "/logout/" + tok} -> logout(tok)
            _                                     -> response(404, map("error", "no route"))
        }
    }
}

cell test SessionsTest {
    rules {
        assert login("ada", "secret").user == "ada"
        assert login("ada", "wrong")._status == 401
        assert whoami("nope")._status == 401
        // round-trip in one isolated assertion
        assert whoami(login("bob", "secret").token).user == "bob"
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check sessions.cell
✓ All checks passed.
$ soma test sessions.cell
test SessionsTest ...
  ✓ assert login("ada", "secret").user == "ada"
  ✓ assert login("ada", "wrong")._status == 401
  ✓ assert whoami("nope")._status == 401
  ✓ assert whoami(login("bob", "secret").token).user == "bob"

4 tests: 4 passed, 0 failed
$ soma verify sessions.cell
Verifying sessions.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
note: the soma.toml beside this file declares [verify] properties; none applies here (no state machine)
VERIFY OK (vacuous — no state machine)

Builtins used

concat, from_json, map, next_id, response, to_string

Source file: /corpus/web/sessions.cell · examples/corpus/web/sessions.cell