Skip to content

filmopen_device

Generated by scripts/package_digest.py; regenerate, never edit.

The device’s identity (Software Specification §6.6b): a P-256 key pair the installation makes the first time it registers, its private half kept in the device’s credential store (CredentialStore.current — DPAPI, the Keychain, the Keystore, the Secret Service; the Portal Specification’s P14), and the device’s id, the SHA-256 of the public half in lower-case hex — not a MAC address, an IMEI or a serial number, which an app can no longer read. Unlike those, the id can prove itself: the device signs with its key.

Flutter. 10 files, 915 lines under lib/; 61 tests in 4 files. Barrel: lib/filmopen_device.dart.

  • filmopen_l10n — uses nothing by name the digest could see
  • filmopen_platform — uses CredentialStore, CredentialStoreUnavailable
  • filmopen_state — uses DeviceAccount, DeviceRegistration, buildStamp, kFilmOpenSiteUrl, runningPlatformName
  • filmopen_store — uses AppLog, LogLevel

Third-party: http, pointycastle.

filmopen_app

What the barrel exports, file by file. A name is class, enum, mixin, extension, typedef, a top-level function, getter, setter or variable; under a class, its public constructors, fields, getters, setters and methods.

  • function Future<bool> claimDeviceName(BuildContext context, {DeviceRegistration? registration, String? hostName}) — Makes sure the device has its permanent name before what needs one goes on (§6.6b).
  • class ClaimDeviceNameDialog — The dialog that claims the device’s permanent name: the host name proposed, the person’s edit, one claim.
    • const ClaimDeviceNameDialog({super.key, required this.registration, required this.proposal})
    • final DeviceRegistration registration — Where the claim goes.
    • final String proposal — The name the box starts with: the host name reduced to the grammar, or empty.
  • variable const kDeviceKeyName — The name the key is kept under in the credential store.
  • class DeviceKey — One installation’s key pair.
    • static DeviceKey? fromPrivateBytes(List<int> bytes) — The key whose private scalar is [bytes], 32 bytes big-endian.
    • static DeviceKey generate([Random? random]) — A new key from [random], Random.secure() unless a test gives one: 32 bytes drawn again until they are a scalar of the curve, which is almost always the first time.
    • static DeviceKey? fromStoredText(String text) — The key kept as [text] (what [storedText] wrote), or null when it is not one.
    • final Uint8List publicKey — The public half: the 65-byte uncompressed SEC1 point, 0x04 \|\| X \|\| Y.
    • final String id — The device’s id: the SHA-256 of [publicKey], 64 lower-case hex digits (K2).
    • final String publicKeyText — [publicKey] as the website takes it: canonical unpadded base64url, 87 characters (K3).
    • String get storedText — What the credential store keeps: the private scalar, 32 bytes, as canonical unpadded base64url.
    • String sign(String text) — [text]’s UTF-8 signed with ECDSA and SHA-256, as the raw 64-byte r \|\| s in canonical unpadded base64url, 86 characters — never ASN.1 DER (K4).
  • function bool verifyDeviceSignature({required List<int> publicKey, required String text, required String signature}) — Whether [signature] (raw r \|\| s, 86 characters of base64url) is [publicKey]’s over [text], taking only what the website takes: a 65-byte uncompressed point on the curve and a canonical signature.
  • function String deviceRegistrationProofText({ required String origin, required String account, required String device, required String signedAt, required St… — The six lines a registration’s proof signs, joined by one \n with no trailing newline (the contract’s PUT /v1/devices/{id}).
  • function String sha256Hex(List<int> bytes) — The SHA-256 of [bytes] in lower-case hex.
  • function String base64UrlText(List<int> bytes) — [bytes] as canonical unpadded base64url: what every standard encoder emits, less its =.
  • function Uint8List? base64UrlBytes(String text) — The bytes of unpadded base64url [text], or null when it is not that.
  • enum DeviceKeyProblem — Why no key could be had, as the log names it.
    • values: noStore, unreadable, unwritable, emptyStore
  • class DeviceKeyUnavailable — No key could be had; [problem] says why.
    • const DeviceKeyUnavailable(this.problem)
    • final DeviceKeyProblem problem
  • function Future<({DeviceKey key, bool made, bool replaced})> openDeviceKey(CredentialStore store) — This installation’s key from [store]: the one it keeps, or a new one made and kept when it keeps none.
  • function String? deviceName() — The web suggests no name: a browser has none of its own to give.
  • function String? deviceNameText(String text) — [text] as a name the website takes (its contract’s name).
  • variable const kDevicePlatforms — The platforms the website knows (its contract’s closed list, K13); another is refused there, so it is not asked.
  • class DeviceRegistrar — The seam’s real implementation, installed by lib/main.dart off the web: once per sign-in, once per launch, and invisible.
    • DeviceRegistrar({ required this.origin, required this.platform, required this.appVersion, required this.buildStamp, this.name, http.Client? client,…
    • final String origin — The site’s origin, https://dev.filmopen.ai or https://filmopen.ai (kFilmOpenSiteUrl).
    • final String platform — runningPlatformName().
    • final String appVersion — 0.1.0+dev: the version and the build.
    • final String buildStamp — The build’s stamp (§6.6a).
    • final String? name — The name the device calls itself, or null (deviceName()).
    • final Duration timeout — How long a request may take before it counts as not made.
    • final void Function()? onRegistered — Told once the website took the device, or answered its name, so that what reads [registeredDevice] and [slug] asks again.
    • Future<void> get idle — The chain of requests settles; for the tests.
  • function bool isDeviceSlug(String text) — Whether [text] has the website’s grammar for a slug: ^[a-z0-9][a-z0-9-]{2,31}$.
  • function String proposeDeviceSlug(String? hostName) — The slug proposed for a device called [hostName]: lowered, every run of other characters one dash, no dash at either end, at most 32 characters; empty where fewer than three are left.
  • class DeviceSlugStore — Where the claimed slug is kept: the app’s preferences, under <accountId>/<deviceId>/slug.
    • String? read(String key) — The value under [key], or null.
    • Future<void> write(String key, String? value) — Keeps [value] under [key]; null removes it.
  • class MemoryDeviceSlugStore — A [DeviceSlugStore] that lasts as long as the process: the tests’, and a build that keeps no preferences.

Files under lib/ the barrel does not reach; nothing outside the package may import them.

  • lib/src/device_name_io.dart: deviceName