[{"data":1,"prerenderedAt":556},["ShallowReactive",2],{"i-lucide:menu":3,"i-simple-icons:github":8,"docs-\u002Fdocs\u002Fpermissions":10,"docs-nav":522,"i-lucide:book-open":540,"i-lucide:download":542,"i-lucide:shield-check":544,"i-lucide:layers":546,"i-lucide:wrench":548,"i-lucide:arrow-left":550,"i-lucide:arrow-right":552,"i-lucide:triangle-alert":554},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"id":11,"title":12,"body":13,"description":514,"extension":515,"icon":516,"meta":517,"navigation":458,"order":90,"path":518,"seo":519,"stem":520,"__hash__":521},"docs\u002Fdocs\u002F2.permissions.md","Permissions",{"type":14,"value":15,"toc":502},"minimark",[16,20,29,34,37,41,44,49,114,128,138,163,170,200,207,257,264,284,308,318,322,325,375,381,388,404,408,411,427,430,498],[17,18,12],"h1",{"id":19},"permissions",[21,22,23,24,28],"p",{},"Anything that can remap your mouse buttons can, by construction, synthesise\nkeystrokes. That is not a flaw in OpenLogi — it is what remapping ",[25,26,27],"em",{},"is",". But it\ndoes mean the permission model deserves more scrutiny than a typical desktop\napp, so this page documents exactly what access is granted, to whom, and for\nhow long.",[30,31,33],"h2",{"id":32},"openlogi-never-runs-as-root","OpenLogi never runs as root",[21,35,36],{},"The application runs entirely as your user. The single privileged action in the\nwhole project is installing a udev rule at setup time. Nothing at runtime is\nelevated, and there is no setuid binary, no system-wide daemon and no polkit\nagent.",[30,38,40],{"id":39},"what-the-rule-grants","What the rule grants",[21,42,43],{},"Two distinct pieces of access, for two different reasons.",[45,46,48],"h3",{"id":47},"reading-and-writing-logitech-hid-endpoints","Reading and writing Logitech HID endpoints",[50,51,56],"pre",{"className":52,"code":53,"language":54,"meta":55,"style":55},"language-ini shiki shiki-themes github-dark-dimmed","SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"046d\", TAG+=\"uaccess\"\nKERNEL==\"hidraw*\", KERNELS==\"*:0000046D:*\", TAG+=\"uaccess\"\n","ini","",[57,58,59,88],"code",{"__ignoreMap":55},[60,61,64,68,72,76,79,82,85],"span",{"class":62,"line":63},"line",1,[60,65,67],{"class":66},"scLw-","SUBSYSTEM",[60,69,71],{"class":70},"s1ain","==",[60,73,75],{"class":74},"sP_-H","\"hidraw\"",[60,77,78],{"class":70},", ATTRS{idVendor}==",[60,80,81],{"class":74},"\"046d\"",[60,83,84],{"class":70},", TAG+=",[60,86,87],{"class":74},"\"uaccess\"\n",[60,89,91,94,96,99,102,105,107,110,112],{"class":62,"line":90},2,[60,92,93],{"class":66},"KERNEL",[60,95,71],{"class":70},[60,97,98],{"class":74},"\"hidraw*\"",[60,100,101],{"class":70},", ",[60,103,104],{"class":66},"KERNELS",[60,106,71],{"class":70},[60,108,109],{"class":74},"\"*:0000046D:*\"",[60,111,84],{"class":70},[60,113,87],{"class":74},[21,115,116,119,120,123,124,127],{},[57,117,118],{},"\u002Fdev\u002Fhidraw*"," defaults to ",[57,121,122],{},"0600 root:root",", and for good reason: raw HID\naccess to a ",[25,125,126],{},"keyboard"," is equivalent to a keylogger. So this access has to be\nnarrow.",[21,129,130,133,134,137],{},[57,131,132],{},"TAG+=\"uaccess\""," asks ",[57,135,136],{},"systemd-logind"," to attach an ACL for the user at the\nactive physical seat. The important properties:",[139,140,141,153,160],"ul",{},[142,143,144,145,149,150],"li",{},"Access is granted ",[146,147,148],"strong",{},"at login"," and revoked ",[146,151,152],{},"at logout",[142,154,155,156,159],{},"It follows the ",[25,157,158],{},"active seat",", so a remote SSH session does not inherit it",[142,161,162],{},"It is not permanent group membership, so it cannot be quietly accumulated",[21,164,165,166,169],{},"The second rule exists because Bluetooth HID devices have no USB ",[57,167,168],{},"idVendor","\nattribute — the vendor id appears in the device path as uppercase hex instead.",[171,172,174],"callout",{"icon":173},"lucide:triangle-alert",[21,175,176,179,180,183,184,187,188,191,192,195,196,199],{},[146,177,178],{},"The filename matters."," ",[57,181,182],{},"systemd"," ships ",[57,185,186],{},"73-seat-late.rules",", which contains\nthe builtin that consumes the ",[57,189,190],{},"uaccess"," tag. udev evaluates rule files in\nlexical order, so a file numbered above 73 sets the tag ",[25,193,194],{},"after"," the builtin has\nalready run and the ACL is silently never applied. OpenLogi's rule is\n",[57,197,198],{},"70-openlogi.rules"," for exactly this reason.",[45,201,203,204],{"id":202},"writing-to-devuinput","Writing to ",[57,205,206],{},"\u002Fdev\u002Fuinput",[50,208,210],{"className":52,"code":209,"language":54,"meta":55,"style":55},"KERNEL==\"uinput\", SUBSYSTEM==\"misc\", OPTIONS+=\"static_node=uinput\", MODE=\"0660\", GROUP=\"openlogi\"\n",[57,211,212],{"__ignoreMap":55},[60,213,214,216,218,221,223,225,227,230,233,236,238,241,244,247,249,252,254],{"class":62,"line":63},[60,215,93],{"class":66},[60,217,71],{"class":70},[60,219,220],{"class":74},"\"uinput\"",[60,222,101],{"class":70},[60,224,67],{"class":66},[60,226,71],{"class":70},[60,228,229],{"class":74},"\"misc\"",[60,231,232],{"class":70},", OPTIONS+=",[60,234,235],{"class":74},"\"static_node=uinput\"",[60,237,101],{"class":70},[60,239,240],{"class":66},"MODE",[60,242,243],{"class":70},"=",[60,245,246],{"class":74},"\"0660\"",[60,248,101],{"class":70},[60,250,251],{"class":66},"GROUP",[60,253,243],{"class":70},[60,255,256],{"class":74},"\"openlogi\"\n",[21,258,259,260,263],{},"Remapped buttons are delivered by synthesising input events through the\nkernel's ",[57,261,262],{},"uinput"," device.",[21,265,266,268,269,272,273,275,276,279,280,283],{},[57,267,262],{}," deliberately does ",[146,270,271],{},"not"," use ",[57,274,190],{},": it is a misc device with no\nseat assignment, so ",[57,277,278],{},"logind"," will not attach an ACL to it. The usual advice in\nthis situation is to join the ",[57,281,282],{},"input"," group — and OpenLogi deliberately does\nnot do that.",[21,285,286,292,293,295,296,299,300,303,304,307],{},[146,287,288,289,291],{},"Why not ",[57,290,282],{},":"," membership in ",[57,294,282],{}," grants ",[25,297,298],{},"read"," access to every\n",[57,301,302],{},"\u002Fdev\u002Finput\u002Fevent*"," node on the system. That is the ability to log every\nkeystroke typed on the machine, in any application, including passwords and\n",[57,305,306],{},"sudo"," prompts. It is a far broader capability than this app needs.",[21,309,310,311,314,315,317],{},"OpenLogi instead creates a dedicated ",[57,312,313],{},"openlogi"," system group that conveys\nexactly one capability — write access to ",[57,316,262],{}," — and nothing else.",[30,319,321],{"id":320},"why-uinput-and-not-the-display-server","Why uinput and not the display server",[21,323,324],{},"Input is synthesised below the display server rather than injected into it.\nThis is a deliberate architectural choice:",[326,327,328,344],"table",{},[329,330,331],"thead",{},[332,333,334,338,341],"tr",{},[335,336,337],"th",{},"Approach",[335,339,340],{},"X11",[335,342,343],{},"Wayland",[345,346,347,364],"tbody",{},[332,348,349,356,359],{},[350,351,352,355],"td",{},[57,353,354],{},"XTEST"," \u002F client-side injection",[350,357,358],{},"Works",[350,360,361],{},[146,362,363],{},"Does not work",[332,365,366,371,373],{},[350,367,368,370],{},[57,369,262],{}," (kernel virtual device)",[350,372,358],{},[350,374,358],{},[21,376,377,378,380],{},"Wayland compositors intentionally refuse client-side input injection, because\npermitting it would let any application type into any other. Writing to\n",[57,379,262],{}," produces a virtual input device that the compositor treats like real\nhardware, so one code path serves both display servers.",[30,382,384,385,387],{"id":383},"what-is-not-granted","What is ",[25,386,271],{}," granted",[139,389,390,393,396,401],{},[142,391,392],{},"No network access — the application contains no networking code",[142,394,395],{},"No access to other users' devices or sessions",[142,397,398,399],{},"No read access to ",[57,400,302],{},[142,402,403],{},"No persistent root, no setuid, no system daemon",[30,405,407],{"id":406},"auditing-it-yourself","Auditing it yourself",[21,409,410],{},"The complete rule file is about 30 lines, and every clause is commented:",[50,412,416],{"className":413,"code":414,"language":415,"meta":55,"style":55},"language-bash shiki shiki-themes github-dark-dimmed","cat \u002Fetc\u002Fudev\u002Frules.d\u002F70-openlogi.rules\n","bash",[57,417,418],{"__ignoreMap":55},[60,419,420,424],{"class":62,"line":63},[60,421,423],{"class":422},"s7B5-","cat",[60,425,426],{"class":74}," \u002Fetc\u002Fudev\u002Frules.d\u002F70-openlogi.rules\n",[21,428,429],{},"To confirm what you were actually granted:",[50,431,433],{"className":413,"code":432,"language":415,"meta":55,"style":55},"# Expect a \"user:\" ACL entry for your username\ngetfacl -p \u002Fdev\u002Fhidraw0\n\n# Expect group \"openlogi\", mode 0660\nls -l \u002Fdev\u002Fuinput\n\n# Confirm you are not in the \"input\" group\nid -nG\n",[57,434,435,441,453,460,466,478,483,489],{"__ignoreMap":55},[60,436,437],{"class":62,"line":63},[60,438,440],{"class":439},"sVrTk","# Expect a \"user:\" ACL entry for your username\n",[60,442,443,446,450],{"class":62,"line":90},[60,444,445],{"class":422},"getfacl",[60,447,449],{"class":448},"sDGpf"," -p",[60,451,452],{"class":74}," \u002Fdev\u002Fhidraw0\n",[60,454,456],{"class":62,"line":455},3,[60,457,459],{"emptyLinePlaceholder":458},true,"\n",[60,461,463],{"class":62,"line":462},4,[60,464,465],{"class":439},"# Expect group \"openlogi\", mode 0660\n",[60,467,469,472,475],{"class":62,"line":468},5,[60,470,471],{"class":422},"ls",[60,473,474],{"class":448}," -l",[60,476,477],{"class":74}," \u002Fdev\u002Fuinput\n",[60,479,481],{"class":62,"line":480},6,[60,482,459],{"emptyLinePlaceholder":458},[60,484,486],{"class":62,"line":485},7,[60,487,488],{"class":439},"# Confirm you are not in the \"input\" group\n",[60,490,492,495],{"class":62,"line":491},8,[60,493,494],{"class":422},"id",[60,496,497],{"class":448}," -nG\n",[499,500,501],"style",{},"html pre.shiki code .scLw-, html code.shiki .scLw-{--shiki-default:#F47067}html pre.shiki code .s1ain, html code.shiki .s1ain{--shiki-default:#ADBAC7}html pre.shiki code .sP_-H, html code.shiki .sP_-H{--shiki-default:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7B5-, html code.shiki .s7B5-{--shiki-default:#F69D50}html pre.shiki code .sVrTk, html code.shiki .sVrTk{--shiki-default:#768390}html pre.shiki code .sDGpf, html code.shiki .sDGpf{--shiki-default:#6CB6FF}",{"title":55,"searchDepth":455,"depth":455,"links":503},[504,505,510,511,513],{"id":32,"depth":90,"text":33},{"id":39,"depth":90,"text":40,"children":506},[507,508],{"id":47,"depth":455,"text":48},{"id":202,"depth":455,"text":509},"Writing to \u002Fdev\u002Fuinput",{"id":320,"depth":90,"text":321},{"id":383,"depth":90,"text":512},"What is not granted",{"id":406,"depth":90,"text":407},"Why OpenLogi never runs as root, how the uaccess ACL works, and why it avoids the input group.","md","lucide:shield-check",{},"\u002Fdocs\u002Fpermissions",{"title":12,"description":514},"docs\u002F2.permissions","gWCXgMEasvOEJVHe2Fub9SKLDTdJ9g5wORIxxYp95Nk",[523,527,531,532,536],{"path":524,"title":525,"icon":526,"order":4},"\u002Fdocs","Introduction","lucide:book-open",{"path":528,"title":529,"icon":530,"order":63},"\u002Fdocs\u002Finstallation","Installation","lucide:download",{"path":518,"title":12,"icon":516,"order":90},{"path":533,"title":534,"icon":535,"order":455},"\u002Fdocs\u002Farchitecture","Architecture","lucide:layers",{"path":537,"title":538,"icon":539,"order":462},"\u002Fdocs\u002Ftroubleshooting","Troubleshooting","lucide:wrench",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":541},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 5v16m8.001-2A2 2 0 0 0 22 17V5a2 2 0 0 0-1.999-2L16 3.002A5 5 0 0 0 12 5a5 5 0 0 0-4-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 1.999 2H8a5 5 0 0 1 4 2a5 5 0 0 1 4-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":543},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 15V3m9 12v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"\u002F>\u003Cpath d=\"m7 10l5 5l5-5\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":545},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\"\u002F>\u003Cpath d=\"m9 12l2 2l4-4\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":547},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z\"\u002F>\u003Cpath d=\"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12\"\u002F>\u003Cpath d=\"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":549},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":551},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m12 19l-7-7l7-7m7 7H5\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":553},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7l7 7l-7 7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":555},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m21.73 18l-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4m0 4h.01\"\u002F>",1789403123747]