Documentation

Ownership & Recovery

Laptop owners, stolen reports, the Crowbar recovery toolkit, repair sticks and the system log.

#Ownership

Every laptop can have an owner, a character, kept by the laptop's serial in the zyke_laptop_owners table, created on start. Ownership blocks nothing: anyone can use, pick up or put away any laptop, and the account's password is what keeps it safe. Ownership is what the Your laptops list in Settings shows, what other resources read through the exports, and what placement.ownerOnlyPickUp checks.

A laptop gets its owner when:

  • a player buys a laptop at the shop;
  • another resource makes it with CreateLaptopMetadata(prebuilt, {owner = identifier}), or calls SetLaptopOwner(serial, identifier);
  • an admin runs /laptop_owner <serverId> for the laptop that player has in their hands;
  • a player takes a laptop nobody owns out of their own inventory. That covers laptops from before ownership, laptops other resources gave without an owner, and released ones;
  • a player sets up a desktop computer nobody owns;
  • without a laptop item (item = false), the character's one laptop is always theirs.

Stealing a laptop, picking it up, using it, reinstalling its OS or swapping its SSD never changes the owner.

#Release

The owner can Release a laptop in Settings > Your laptops before selling or giving it away. It then has no owner, and whoever takes it out next becomes its owner. Also sign it out of my account signs the drive out of the owner's Nimbus account at the same time. Without a laptop item (item = false) a laptop can't be released.

#Reported Stolen

The owner can mark a laptop Report stolen, and later Mark as found. It is a flag only the exports read; the laptop itself works as before. A new owner clears it.

Only the owning character can release a laptop or report it stolen. Being signed in to its account isn't enough.

#Owner-Only Pick Up

lua
placement = {
    -- Only the laptop's owner can pick it up, or the character who put it down when it has no owner
    ownerOnlyPickUp = false,
},

Off, anyone can carry a laptop off, as Crowbar expects of stolen laptops. Without a laptop item only the owner can pick it up either way.

#Setting an Owner as Admin

/laptop_owner <serverId> makes that player's character the owner of the laptop in their hands. It needs the ACE command.laptop_owner and also works from the server console. See Commands.

add_ace group.admin command.laptop_owner allow

The server event zyke_laptop:LaptopOwnerChanged(serial, identifier, source) fires on every change, with identifier nil once released. source is "shop", "claim", "admin", "character", "release" or the resource that called the export. zyke_laptop:LaptopReportedStolen(plyId, serial, stolen) fires when the owner reports or withdraws. Both are logged through the OwnerChanged and ReportedStolen webhooks.

#Crowbar Recovery Toolkit

recovery_usb is Crowbar, the toolkit a thief boots from the boot menu on a laptop they stole. It starts a live Lumen that skips sign-in and opens Crowbar, which reads the laptop's drive:

  • the OS, device name and serial;
  • the account's username and password hint, and on Facade and Solace how strong the password is;
  • the system log;
  • the home folder and browser history, when the drive isn't locked. A Shroud key saved in the home folder is pointed out.

A laptop without an SSD has nothing to read. A wiped drive, or one that only ever ran Veil, shows "Nothing to Recover".

#The Timer

Crowbar then works on the password. Its timer is kept on the drive, so it survives restarts. It only runs while a player keeps Crowbar open on that laptop, stays at it and still has the stick, and keeps its progress in between.

How long it takes comes from recovery.durations, by the OS on the drive and how strong the password is. The server only keeps the strength tier next to the hash, worked out when the password is set:

TierPassword
trivialUnder 6 characters, a common password such as 123456 or password, or one character repeated.
weakAnything that isn't trivial, fair or strong.
fair8 characters or more, using two of lower case, upper case, digits and symbols. Accounts from before the tier was kept count as fair.
strong12 characters or more using three of them, or 16 or more using two.

A drive linked to a Nimbus account runs on the account's tier.

#What Crowbar Finds

OSWhat Crowbar finds
Facade 11 ProThe home folder and browser history at once. The short timer only gates setting a new password.
SolaceThe same as Facade, with the same short timer.
LumenThe log and the account's name. The home folder and history stay locked until the timer finishes, and a strong password never finishes: Crowbar runs out of guesses and the drive stays locked.
VeilNothing. Veil never writes to the drive.

Once the timer is done, Crowbar can set a new password for the account; the username stays. The server fires zyke_laptop:LaptopDriveUnlocked(serial, plyId), with the drive's serial and the player whose toolkit worked on it, and logs it through the DriveUnlocked webhook. The drive stays open to Crowbar until an OS is installed on it again. A new password restarts an unfinished timer.

On a drive linked to Nimbus, Crowbar gets a frozen local copy of the account's data, see Crowbar on Linked Drives.

#Configuration

lua
recovery = {
    enabled = true,
    -- Item that shows up in the boot menu, false offers the toolkit to everyone
    item = "recovery_usb",
    -- Seconds Crowbar works on a password, by OS and strength tier
    durations = {
        facade = {trivial = 30, weak = 45, fair = 60, strong = 180},
        lumen = {trivial = 120, weak = 300, fair = 1200, strong = 1200},
        solace = {trivial = 30, weak = 45, fair = 60, strong = 180},
    },
    -- Tiers Crowbar gives up on once their duration is over, the drive stays locked
    exhausts = {
        lumen = {strong = true},
    },
    -- Lines each drive's system log keeps, the oldest go first
    maxLogs = 100,
    -- OSes whose installer stick can reset the local password of its own drive without erasing it
    repair = {facade = true, solace = true},
},

#Repair Sticks

For every OS recovery.repair lists, the installer stick of the OS already on the drive offers two choices in the boot menu:

  • Repair: reset the local password keeps everything on the drive and sets a new password for its local account. The old password isn't needed.
  • Erase the drive and reinstall works as any installer does.

By default Facade and Solace have this weakness, and Lumen's stick only reinstalls. Leave an OS out, or set it to false, to have its installer only erase and reinstall. A worn-out SSD that turned read-only refuses both.

A reset fires zyke_laptop:LaptopPasswordReset(plyId, serial, drive) and is logged through the PasswordReset webhook. On a drive linked to Nimbus it leaves a local copy and never changes the Nimbus password.

#System Log

Facade, Lumen and Solace keep a system log on the drive. Only the server writes it, and Crowbar and other server resources read it. It keeps the last recovery.maxLogs lines, and a line that repeats the one before within 30 seconds is dropped.

KindLogged when
bootThe laptop booted, with device "drive" or "usb". A USB boot never says which stick.
signIn, signInFailedAn account signed in, or a wrong password was typed for it.
accountCreatedSetup or an administrator made an account.
passwordChanged, passwordResetThe password was changed, or reset with Forgot password, a repair stick, Crowbar or an administrator.
installAn installer put an OS on the drive.
networkAn OS booted from the drive joined a network, the phone's hotspot by its name.
cloudLinked, cloudSignedOutThe drive was linked to a Nimbus account, or left it.

Veil never writes to the drive, so its boots only leave the boot line with device = "usb".

#For Police Resources

The laptop's serial is in Shroud's chat traces and the browser's visit traces when the sender's OS or tier records it. Turn it into a character, check for a stolen report, and read the drive of a seized laptop:

lua
---@param serial string
local function investigate(serial)
    local owner = exports["zyke_laptop"]:GetLaptopOwner(serial)
    local stolen = exports["zyke_laptop"]:IsLaptopReportedStolen(serial)

    -- Oldest first: boots, sign-ins, failed passwords and the networks it joined
    for _, entry in ipairs(exports["zyke_laptop"]:GetLaptopLogs(serial)) do
        if (entry.kind == "network") then print(("%s joined %s"):format(os.date("%c", entry.at), entry.ssid)) end
    end

    -- What Crowbar would see, locked sections left out
    local report = exports["zyke_laptop"]:GetLaptopRecoveryReport(serial)
end

The drive exports take the SSD's serial, or the laptop's serial while the laptop is out. Leave the owner lookup out if your server doesn't want police to trace a laptop to a character.

See Exports & Events for GetLaptopOwner, SetLaptopOwner, ReleaseLaptopOwner, GetCharacterLaptops, IsLaptopReportedStolen, GetLaptopLogs, GetLaptopRecoveryReport and IsLaptopDriveUnlocked.