Table of Contents

Log-in Detection with Attachments

Log-In Detection (LID™) provides a way to determine that the user has logged-in from a script contained in an attachment.

LID™ exploits event-handlers by noticing the following distinction:

When the object is detached, LID™ sets a flag (logon := -1) on a linked primitive using the key value data API marking whether the primitive has been attached or detached. A linked primitive is chosen because the root primitive is unable to retain its description once the object is detached. The key value data API is used for consistency but any custom implementation that is able to write to a linked-primitive's description will suffice.

When the object is attached or the avatar logs on, LID™ increments the flag (logon := logon + 1) and resets the script using llResetScript, thus:

Lastly, when the avatar logs out, the attach event does not run.

Security Implications

It should be noted that event handlers do not run atomically and may be interrupted on the avatar's whims. This means that LID™ is susceptible to race conditions (generally, the attach event handler is susceptible to race conditions (so is on_rez)). This can be verified by quickly attaching and detaching the object containing a LID™ script which may trigger LID™ when it is not supposed to. The implication for LID™ is that, on interruption of the attach event handler, the variable login may be set to:

Practical Applications using Logging-In Detection

Generic LID™ Code

Note that resetting the script in the on_rez event handler is not necessary because the attach event handler resets the script instead - this applies only to worn objects.

///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
default {
    state_entry() {
        // LID™ reasoning - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
        // if LID™, then login = 1
        // else login = 0 - script running | parameter undefined
        if((integer)wasKeyValueGet("login", llGetObjectDesc()) > 0) {
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            llOwnerSay("[LID™]: The user has logged-in wearing this object.");
            return;
        }
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
        llOwnerSay("[LID™]: The script was restarted.");
    }
 
    // LID™ reasoning - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
    // order: on_rez -> attach
    //
    // if object attached, then login := login+1
    // else login := -1
    attach(key id) {
        // attached
        if(id != NULL_KEY && llGetAttached() != 0) {
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", (string)((integer)wasKeyValueGet("login", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))+1), llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            // Reset script for llGetOwner() bugture.
            llResetScript();
        }
        // detached
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "-1", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
    }
    // login = 1 after object attached
    //       = -1 after object detached
}