From 20a47d944425bb5a10a1e612165f32edd334177a Mon Sep 17 00:00:00 2001 From: Nadja Reitzenstein Date: Sat, 12 Mar 2022 01:28:07 +0100 Subject: [PATCH] Improve examples --- bffhd/actors/shelly.rs | 0 examples/actor.py | 179 ++++++++++++++++++++++++++++++++++ examples/actors.dhall | 11 --- examples/bffh.dhall | 35 ++++++- examples/initiators.dhall | 1 - examples/machines.dhall | 28 ------ examples/pass.toml | 1 - examples/roles.dhall | 14 --- examples/self-signed-cert.pem | 19 ++++ examples/self-signed-key.pem | 28 ++++++ examples/types/Machine.dhall | 15 --- examples/users.toml | 14 --- 12 files changed, 258 insertions(+), 87 deletions(-) create mode 100644 bffhd/actors/shelly.rs create mode 100755 examples/actor.py delete mode 100644 examples/actors.dhall delete mode 100644 examples/initiators.dhall delete mode 100644 examples/machines.dhall delete mode 100644 examples/pass.toml delete mode 100644 examples/roles.dhall create mode 100644 examples/self-signed-cert.pem create mode 100644 examples/self-signed-key.pem delete mode 100644 examples/types/Machine.dhall diff --git a/bffhd/actors/shelly.rs b/bffhd/actors/shelly.rs new file mode 100644 index 0000000..e69de29 diff --git a/examples/actor.py b/examples/actor.py new file mode 100755 index 0000000..489260c --- /dev/null +++ b/examples/actor.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 + +import sys +import argparse + +def on_free(args, actor_name): + """ + Function called when the state of the connected machine changes to Free + again + """ + if args.verbose > 2: + print("on_free called!") + + if actor_name == "DoorControl1": + # Do whatever you want to do in case `DoorControl1` is returned back to free. + # Keep in mind that process actors should return quickly to not miss + # updates, so if you need to do things that take a while fork a new + # process e.g. with the `subprocess` Module + print("I'm locking door 1!") + pass + elif actor_name == "DoorControl2": + print("I'm locking door 2!") + pass # Close a different door + else: + if not args.quiet: + print("process called with unknown id %s for state `Free`" % actor_name) + # It's a good idea to exit with an error code in case something + # unexpected happens. + # The process module logs everything printed to stdout by actors into + # the server log, but marks them as `Error` in case the actor process + # exits with a code != 0, making debugging somewhat easier. + exit(-1) + +def on_use(args, actor_name, user_id): + """ + Function called when an user takes control of the connected machine + + user_id contains the UID of the user now using the machine + """ + if args.verbose > 2: + print("on_use called!") + if actor_name == "DoorControl1": + print("I'm opening door 1 for 10 seconds!") + pass # Open door one + elif actor_name == "DoorControl2": + print("I'm opening door 2 for 10 seconds!") + pass # Open a different door + else: + if not args.quiet: + print("process called with unknown id %s for state `InUse`" % actor_name) + # It's a good idea to exit with an error code in case something + # unexpected happens. + # The process module logs everything printed to stdout by actors into + # the server log, but marks them as `Error` in case the actor process + # exits with a code != 0, making debugging somewhat easier. + exit(-1) + +def on_tocheck(args, actor_name, user_id): + """ + Function called when an user returns control and the connected machine is + configured to go to state `ToCheck` instead of `Free` in that case. + + user_id contains the UID of the manager expected to check the machine. + The user that used the machine beforehand has to be taken from the last + user field using the API (via e.g. the mobile app) + """ + if args.verbose > 2: + print("on_tocheck called!") + if not args.quiet: + print("process called with unexpected combo id %s and state 'ToCheck'" % actor_name) + exit(-1) + +def on_blocked(args, actor_name, user_id): + """ + Function called when an manager marks the connected machine as `Blocked` + + user_id contains the UID of the manager that blocked the machine + """ + if args.verbose > 2: + print("on_blocked called!") + if not args.quiet: + print("process called with unexpected combo id %s and state 'Blocked'" % actor_name) + exit(-1) + +def on_disabled(args, actor_name): + """ + Function called when the connected machine is marked `Disabled` + """ + if not args.quiet: + print("process called with unexpected combo id %s and state 'Disabled'" % actor_name) + exit(-1) + +def on_reserve(args, actor_name, user_id): + """ + Function called when the connected machine has been reserved by somebody. + + user_id contains the UID of the reserving user. + """ + if not args.quiet: + print("process called with unexpected combo id %s and state 'Reserved'" % actor_name) + exit(-1) + + +def main(args): + """ + Python example actor + + This is an example how to use the `process` actor type to run a Python script. + """ + + if args.verbose is not None: + if args.verbose == 1: + print("verbose output enabled") + elif args.verbose == 2: + print("loud output enabled!") + elif args.verbose == 3: + print("LOUD output enabled!!!") + elif args.verbose > 4: + print("Okay stop you're being ridiculous.") + sys.exit(-2) + else: + args.verbose = 0 + + # You could also check the actor name here and call different functions + # depending on that variable instead of passing it to the state change + # methods. + + new_state = args.state + if new_state == "free": + on_free(args, args.name) + elif new_state == "inuse": + on_use(args, args.name, args.userid) + elif new_state == "tocheck": + on_tocheck(args, args.name, args.userid) + elif new_state == "blocked": + on_blocked(args, args.name, args.userid) + elif new_state == "disabled": + on_disabled(args, args.name) + elif new_state == "reserved": + on_reserve(args, args.name, args.userid) + else: + print("Process actor called with unknown state %s" % new_state) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + # Parameters are passed to the Process actor as follows: + # 1. the contents of params.args, split by whitespace as separate args + # 2. the configured id of the actor (e.g. "DoorControl1") + # 3. the new state as one of [free|inuse|tocheck|blocked|disabled|reserved] + + parser.add_argument("-q", "--quiet", help="be less verbose", action="store_true") + parser.add_argument("-v", "--verbose", help="be more verbose", action="count") + + parser.add_argument("name", + help="name of this actor as configured in bffh.dhall" + ) + + # We parse the new state using subparsers so that we only require a userid + # in case it's a state that sets one. + subparsers = parser.add_subparsers(required=True, dest="state") + + parser_free = subparsers.add_parser("free") + + parser_inuse = subparsers.add_parser("inuse") + parser_inuse.add_argument("userid", help="The user that is now using the machine") + + parser_tocheck = subparsers.add_parser("tocheck") + parser_tocheck.add_argument("userid", help="The user that should go check the machine") + + parser_blocked = subparsers.add_parser("blocked") + parser_blocked.add_argument("userid", help="The user that marked the machine as blocked") + + parser_disabled = subparsers.add_parser("disabled") + + parser_reserved = subparsers.add_parser("reserved") + parser_reserved.add_argument("userid", help="The user that reserved the machine") + + args = parser.parse_args() + main(args) diff --git a/examples/actors.dhall b/examples/actors.dhall deleted file mode 100644 index 495d552..0000000 --- a/examples/actors.dhall +++ /dev/null @@ -1,11 +0,0 @@ -{ Shelly_1234 = { module = "Shelly", params = {=} } -, Bash = - { module = "Process" - , params = { cmd = "./examples/actor.sh", args = "your ad could be here" } - } -, Bash2 = - { module = "Process" - , params = { cmd = "./examples/actor.sh", args = "this is a different one" } - } -, FailBash = { module = "Process", params.cmd = "./examples/fail-actor.sh" } -} diff --git a/examples/bffh.dhall b/examples/bffh.dhall index 2a7ae5d..b0a6a31 100644 --- a/examples/bffh.dhall +++ b/examples/bffh.dhall @@ -38,6 +38,11 @@ -- access into them. db_path = "/tmp/bffh", + -- Audit log path. Bffh will log state changes into this file, one per line. + -- Audit log entries are for now JSON: + -- {"timestamp":1641497361,"machine":"Testmachine","state":{"state":{"InUse":{"uid":"Testuser","subuid":null,"realm":null}}}} + auditlog_path = "/tmp/bffh.audit", + -- In dhall you can also easily import definitions from other files, e.g. you could write -- roles = ./roles.dhall roles = { @@ -175,6 +180,30 @@ args = "your ad could be here" } }, + + DoorControl1 = { + -- This actor calls the actor.py script in examples/ + -- It gets passed it's own name, so you can have several actors + -- from the same script. + -- If you need to pass more arguments to the command you can use the `args` key in + -- `params` as is done with the actor `Bash` + module = "Process", + -- the `args` are passed in front of all other parameters so they are best suited to + -- optional parameters like e.g. the verboseness + params = { cmd = "./examples/actor.py", args = "-vvv" } + }, + DoorControl2 = { + module = "Process", + params = { cmd = "./examples/actor.py" } + }, + DoorControl3 = { + -- This is an example for how it looks like if an actor is misconfigured. + -- the actor.py doesn't know anything about DoorControl3 and, if this actor is enabled, + -- will return with an error showing up in the server logs. + module = "Process", + params = { cmd = "./examples/actor.py" } + }, + Bash2 = { module = "Process", params = { cmd = "./examples/actor.sh" , args = "this is a different one" }}, FailBash = { module = "Process", params = { cmd = "./examples/fail-actor.sh" }} }, @@ -195,11 +224,11 @@ initiators = {=}, -- The "Dummy" initiator will try to use and return a machine as the given user every few seconds. It's good to -- test your system but will spam your log so is disabled by default. - --{ Initiator = { module = "Dummy", params = { uid = "Testuser" } } } + --initiators = { Initiator = { module = "Dummy", params = { uid = "Testuser" } } }, -- Linking up machines to initiators. Similar to actors a machine can have several initiators assigned but an -- initiator can only be assigned to one machine. -- The below is once again how you have to define *no* initiators. init_connections = [] : List { machine : Text, initiator : Text } - -- init_connections = [{ machine = "Testmachine", initiator = "Initiator" }] -} \ No newline at end of file + --init_connections = [{ machine = "Testmachine", initiator = "Initiator" }] +} diff --git a/examples/initiators.dhall b/examples/initiators.dhall deleted file mode 100644 index 339130f..0000000 --- a/examples/initiators.dhall +++ /dev/null @@ -1 +0,0 @@ -{=} diff --git a/examples/machines.dhall b/examples/machines.dhall deleted file mode 100644 index 6a145eb..0000000 --- a/examples/machines.dhall +++ /dev/null @@ -1,28 +0,0 @@ -{ Testmachine = - { description = Some "A test machine" - , name = "Textmachine" - - , manage = "lab.test.admin" - , read = "lab.test.read" - , write = "lab.test.write" - , disclose = "lab.test.read" - } -, Another = - { description = Some "Another test machine" - , name = "Another" - - , disclose = "lab.test.read" - , manage = "lab.test.admin" - , read = "lab.test.read" - , write = "lab.test.write" - }, - Yetmore = - { description = Some "Yet more test machines" - , name = "Yetmore" - - , disclose = "lab.test.read" - , manage = "lab.test.admin" - , read = "lab.test.read" - , write = "lab.test.write" - } -} diff --git a/examples/pass.toml b/examples/pass.toml deleted file mode 100644 index 6d4855d..0000000 --- a/examples/pass.toml +++ /dev/null @@ -1 +0,0 @@ -Testuser = "secret" diff --git a/examples/roles.dhall b/examples/roles.dhall deleted file mode 100644 index 75a4d4b..0000000 --- a/examples/roles.dhall +++ /dev/null @@ -1,14 +0,0 @@ -{ testrole = - { permissions = [ "lab.test.*" ] } -, somerole = - { parents = ["testparent"] - , permissions = [ "lab.some.admin" ] - } -, testparent = - { permissions = - [ "lab.some.write" - , "lab.some.read" - , "lab.some.disclose" - ] - } -} diff --git a/examples/self-signed-cert.pem b/examples/self-signed-cert.pem new file mode 100644 index 0000000..89f056d --- /dev/null +++ b/examples/self-signed-cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFzCCAf+gAwIBAgIUDr+1F3zzyza+soLtiurKEXW9pGIwDQYJKoZIhvcNAQEL +BQAwGzEZMBcGA1UEAwwQYmZmaC1kZXZlbG9wbWVudDAeFw0yMTEyMDkxODQ2Mjla +Fw0zMTEyMDkxODQ2MjlaMBsxGTAXBgNVBAMMEGJmZmgtZGV2ZWxvcG1lbnQwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGwNy7yGaURR08dWfoDmnJeyx1 +0FVRmozoGCIb3Oj6c2t+84QUxqTdknE7Cdcz5Wi1o0x2CWPZG4z1vgTaCcJVhcME +hxn+7eK1NtDQEjs8Ojs7uaraVvooIe8R7jat0qs7Dmf8RO9P0I4MMZlvijhI7aLw +0C6vNsr1ebeppIiwO5aUuCGuKqxJGghHeqZv18ZcPayunyNrxMC6uyX7y6nUVkfq +x0m9gDsN112Iv9Dd/ZE5Gxivm8jZvVUGZgJD2szK7zbeCDeo5aU3cRWfYaoN0QDx +AKmo4bjciJzfMDDgvcIBq9lGS3FxEv394Mc5YX/ZdP+KRTiHcYCXfBzr3B6HAgMB +AAGjUzBRMB0GA1UdDgQWBBTtUvvWXlo5tU8cEoxbs5UJdodOVDAfBgNVHSMEGDAW +gBTtUvvWXlo5tU8cEoxbs5UJdodOVDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQAB3IxRnWi/LrxCvlHNaWEi3ZvlbN+KpegWZeKtjHwQoizhR/Fi +SMC7z4y6trJE7LXUOSb9Pu8QQSvpVQZd3W4XCPZMl10Lt7iV8vc3pVviCseDnT9r +X1gXdbeuyYm9lE8KtlhX03jD/CiEx7Qe/q8Rc20AQIKAAJzvl7sXU2tmJ5kpzMEO +v5czlLaX2ajlD/QMgNBUuDyw6wPo3wx9Khph484RygN2LHeT6kfu/PBiF0dGDTUu +mgxg4K0GfwTcHgtz5Bag/HyuuJEKx8Wv7jth59PyKPT+lMVBznxIm3gLS5U+Nnr1 +uAws8dgLXRlPo5HJORuJCcZWVBClruZUpyDT +-----END CERTIFICATE----- diff --git a/examples/self-signed-key.pem b/examples/self-signed-key.pem new file mode 100644 index 0000000..08139db --- /dev/null +++ b/examples/self-signed-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGwNy7yGaURR08 +dWfoDmnJeyx10FVRmozoGCIb3Oj6c2t+84QUxqTdknE7Cdcz5Wi1o0x2CWPZG4z1 +vgTaCcJVhcMEhxn+7eK1NtDQEjs8Ojs7uaraVvooIe8R7jat0qs7Dmf8RO9P0I4M +MZlvijhI7aLw0C6vNsr1ebeppIiwO5aUuCGuKqxJGghHeqZv18ZcPayunyNrxMC6 +uyX7y6nUVkfqx0m9gDsN112Iv9Dd/ZE5Gxivm8jZvVUGZgJD2szK7zbeCDeo5aU3 +cRWfYaoN0QDxAKmo4bjciJzfMDDgvcIBq9lGS3FxEv394Mc5YX/ZdP+KRTiHcYCX +fBzr3B6HAgMBAAECggEAS5DGG6ssvRCt9e+ZatQYCl+HXt+voJAHJLMQPNG3zokV +hLXnMNL5mbh0zoKGTJfbQLvudS5KxR/BbykoxRFSzptFszH+gztEp6tIpuNXnCVz +odiMiejpwVptf763EU14hsKKbJJ0/j6H00EEWjEOB0Q6YB52sW0+qyf02U3SHlZN +k2PZYkpHi3YCONtOGj7jOdW7M3RfvcBNg9EW7fZc1KkiRAlscUAYLMkKcOLevil0 +lUuF/JWj4iH22Oq6+JeSiecf6izF6lyIGvMXPry+woa8Iq0BBdmbZsK7r/Pa+wlz ++E6xHGn2rcyrnYB2pPc+RfHhYlodaOo69DxAYlRYaQKBgQDxnKySmlcfHe8lMqR4 +2LvqMyGjNRo2+q9VZYej2mvr6+TGyd7Op/fRJ1t5f9DgtINomNQYSOtYAsPiEnl+ +43z2N/Rdh6XSmOj4gLkDeiYNSpy86L/F39uCWZpkkqiy2zxYLWOs15MA0GWOtQGh +dz4cM0b/jyZOdHZR//L5WiMLawKBgQDSltEfQKqCEKJTqp4SU9BCHQmyheIjepY2 +eKakgcsjpFjRBK2VrUalDLOQV74rtd7wp8F8kqqPJpRshb+oVuDCg6JB17UxYd34 +iB+5cMdLRpg8f0HOqcYz4KOql2QhJQhFc3jzY7n1piPEhFO/MqFwmlUB4RdgJ3ix +HqX+F/T8VQKBgGos76l9KcwC25T9LEnu9KV20tFmBJ8kiuh8NZ9L3SFQCLlS/RbT +uZOwOAKsqJ4WtajBgHMrmECU9n/inoGkdsW80SZI9hYWHEsYRjXA9/ffUgGyRpQu +S8h8l9yalogC0AHv8F2EXpV8/yQ3ZwAN5r19yzWDMtJHW7etQplRgxUBAoGAGeOy +t+3iSHU1D6YlIsmtC8O4Int1LrluaCnzCrxuNeaJiMDTelhAHCBwnuk6lvMYAmwN +THxXfZvXmXPj+RUdMqyuMPwM6ZJHkLtjcw/bYHTAWIeolnimxk/yrxFHnQ+Jcchd +cUasYPfY49sE1Lerw0Ul+EIs9oRDwTqsW42kb7UCgYEA2y+oc7Fz2eq38hSbTfy7 +OcATtny+xQ1+4IELtQIP7VctkMInJs57J+vS//IT41P0L2K1YjvL8RacnvG7yMvP +GnwHBcKgvL6zuoy11I3zPPYtbKGwcJoVGomPX7W0csfl4gdST3uugd9iCDEB8NsS +QmOYM/dk8x8aWpndBjRF5ig= +-----END PRIVATE KEY----- diff --git a/examples/types/Machine.dhall b/examples/types/Machine.dhall deleted file mode 100644 index c48c85f..0000000 --- a/examples/types/Machine.dhall +++ /dev/null @@ -1,15 +0,0 @@ -let Map = https://prelude.dhall-lang.org/v20.2.0/Map/Type - sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed - -let Machine = - { Type = - { description : Optional Text - , manage : Text - , write : Text - , read : Text - , disclose : Text - } - , default = { description = None } - } - -in Machine diff --git a/examples/users.toml b/examples/users.toml index 6e1009c..719f2fb 100644 --- a/examples/users.toml +++ b/examples/users.toml @@ -11,17 +11,3 @@ passwd = "secret" # It will get stored in the `kv` field in UserData. # This is not used for anything at the moment noot = "noot!" - -[Differentuser] -# Define them in roles.toml as well -roles = ["somerole/internal", "testrole/internal"] - -# If two or more users want to use the same machine at once the higher prio -# wins -priority = 0 - -passwd = "secret" - -# You can add whatever random data you want. -# It will get stored in the `kv` field in UserData. -noot = "noot!"