We authorize a synthetic session for a sensitive operation and prepare a request. Before the request reaches its execution boundary the user locks the session. Checking authorization only when the interface prepared the request lets that old request continue after the lock appears to have taken effect.
Our independent JavaScript fixture gives each authorization grant an expiry and a generation number. A manual lock removes the grant and changes the generation. No credentials or key material exist in the fixture and it performs no signing or wallet operation.
State what the lock revokes
A lock can revoke an application session without revoking a blockchain private key. If a service retains a decrypted signing key then the meaning of locked depends on how that key becomes inaccessible to the execution path. A UI flag alone does not change key custody.
We model a narrower statement. The application refuses a protected action unless it holds a current grant at the moment of execution. That statement has a testable state boundary. It does not claim that an attacker controlling the process cannot read memory or bypass application code.
function authorized(ticket, now) {
return (
grant !== null &&
ticket.epoch === epoch &&
ticket.epoch === grant.epoch &&
now < grant.expires
);
}A request ticket records the generation that was authorized when the operation was prepared. Manual locking increments the generation so an old ticket remains invalid even if the same user unlocks a new session immediately afterward. The execution path evaluates a grant's expiry even when periodic cleanup has not run.
Cleanup is not enforcement
A background task can delete expired grants to reduce retained state. Its scheduling delay should not extend authorization. If expiry is enforced only by that task then a paused worker or a busy event loop can leave an expired grant usable.
The fixture compares the current clock against the stored expiry whenever the protected operation is checked. At the exact expiry instant the grant is invalid. We use an injected clock so the boundary test is deterministic and does not depend on a timer firing during a test run.
We validate the grant again at the protected execution boundary because the time spent waiting in a queue can outlast the original authorization and a request that was permitted when it entered the interface must not retain that permission indefinitely after the user has locked the session or its expiry has passed.
For an operation that performs several asynchronous steps the final authorization check should precede the irreversible action. A lock arriving after a transaction has already been signed or broadcast cannot retroactively withdraw that artifact. The interface needs to describe the boundary it can actually control.
Keep verification separate from secret retention
A PIN can gate access to encrypted material but a short human chosen value is not a high entropy encryption key by itself. A real key protection design needs an appropriate derivation scheme and attempt controls. Storing a raw PIN for convenience adds a separate secret lifecycle that needs justification.
This example stores only symbolic grants so its tests do not certify any encryption implementation. A Python Telegram bot or another conversational interface still needs to ensure that sensitive commands invoke the same authorization boundary and that errors do not log secret inputs.
Expired, locked and previous-generation requests rejected
8 assertions passedThe assertions cover manual lock and expiry along with the stale ticket that remains invalid after a fresh unlock. We also check that the new ticket works before its expiry. This distinguishes a correct invalidation rule from a blanket rejection that merely makes every test operation fail.
Test the queued operation
The difficult case is work already prepared when revocation happens. A unit test can enqueue a symbolic action and then lock before execution. An integration test should hold the actual signing or submission boundary behind a controllable barrier so it can establish the same order of events.
For multiple workers a process local generation counter is insufficient unless requests and grants share the same authoritative state. The revocation needs propagation semantics and a declared failure policy if that authority cannot be reached. A cache of authorization decisions should not silently extend permission during an outage.
Two concurrent requests make the revocation boundary visible. Lock between their final checks and record which operation had already crossed the irreversible boundary so every remaining request can be tested against the changed generation.