mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2025-04-20 19:26:26 +02:00
Compare commits
7 Commits
v0.4.3
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
314145084e | |||
5e0d615ada | |||
e4b7aa8766 | |||
bbf0e77571 | |||
40ca2acdb7 | |||
3e29df8b2c | |||
fdde8a933c |
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,4 +1,4 @@
|
|||||||
[submodule "schema"]
|
[submodule "schema"]
|
||||||
path = api/schema
|
path = api/schema
|
||||||
url = ../fabaccess-api
|
url = https://gitlab.com/fabinfra/fabaccess/fabaccess-api
|
||||||
branch = main
|
branch = main
|
||||||
|
112
CONTRIBUTING.md
112
CONTRIBUTING.md
@ -2,120 +2,38 @@
|
|||||||
|
|
||||||
Thank you for your interest in helping out the FabAccess system!
|
Thank you for your interest in helping out the FabAccess system!
|
||||||
|
|
||||||
You found a bug, an exploit or a feature that doesn't work like it's documented? Please tell us
|
You found a bug, an exploit or a feature that doesn't work like it's documented? Please tell us about it, see [Issues](#issues)
|
||||||
about it, see [Issues](#issues)
|
|
||||||
|
|
||||||
You have a feature request? Great, check out the paragraph on [Feature Requests](#feature-requests)
|
You have a feature request? Great, check out the paragraph on [Feature Requests](#feature-requests)
|
||||||
|
|
||||||
## Issues
|
## Issues
|
||||||
|
|
||||||
While we try to not have any bugs or exploits or documentation bugs we're not perfect either. Thanks
|
While we try to not have any bugs or exploits or documentation bugs we're not perfect either. Thanks for helping us out!
|
||||||
for helping us out!
|
|
||||||
|
|
||||||
We have labels that help us sort issues better, so if you know what would be the correct ones,
|
We have labels that help us sort issues better, so if you know what would be the correct ones, please tag your issue with one or multiple keywords. See [Labels](https://gitlab.com/fabinfra/fabaccess/bffh/-/labels) to get an overview of all keywords and their use case.
|
||||||
please tag your issue:
|
|
||||||
- `documentation` if it's an documentation issue, be it lacking docs or even worse wrong docs.
|
|
||||||
- `bug` is for software bugs, unexpected behaviour, crashes and so on.
|
|
||||||
- `exploit` for any bugs that may be used as RCE, to escalate priviledges or some-such.
|
|
||||||
Don't worry if you aren't sure about the correct labels, an issue opened with no labels is much
|
|
||||||
better than no knowing about the issue!
|
|
||||||
|
|
||||||
Especially for bugs and exploits, please mark your issue as "confidential" if you think it impacts
|
Especially for **bugs** and **exploits**, please mark your issue as "confidential" if you think it impacts the `stable` branch. If you're not sure, mark it as confidential anyway. It's easier to publish information than it is to un-publish information. You may also contact as by [mail](https://fab-access.org/impressum).
|
||||||
the `stable` branch. If you're not sure, mark it as confidential anyway. It's easier to publish
|
|
||||||
information than it is to un-publish information.
|
|
||||||
|
|
||||||
If you found an exploit and it's high-impact enough that you do not want to open an issue but
|
|
||||||
instead want direct contact with the developers, you can find public keys respectively fingerprints
|
|
||||||
for GPG, XMPP+OMEMO and Matrix+MegOlm in the git repository as blobs with tags assigned to them.
|
|
||||||
|
|
||||||
You can import the gpg key for dequbed either from the repository like so:
|
|
||||||
```
|
|
||||||
$ git cat-file -p keys/dequbed/gpg | gpg --import-key
|
|
||||||
```
|
|
||||||
Or from your local trusted gpg keyserver, and/or verify it using [keybase](https://keybase.io/dequbed)
|
|
||||||
This key is also used to sign the other tags so to verify them you can run e.g.
|
|
||||||
```
|
|
||||||
$ git tag -v keys/dequbed/xmpp+omemo
|
|
||||||
```
|
|
||||||
|
|
||||||
## Feature Requests
|
## Feature Requests
|
||||||
|
|
||||||
We also like new feature requests of course!
|
We also like new feature requests of course!
|
||||||
But before you open an issue in this repo for a feature request, please first check a few things:
|
But before you open an issue in this repo for a feature request, please first check a few things:
|
||||||
1. Is it a feature that needs to be implemented in more than just the backend server? For example,
|
|
||||||
is it something also having a GUI-component or something that you want to be able to do via the
|
1. Is it a feature that needs to be implemented in more than just the backend server? For example, is it something also having a GUI-component or something that you want to be able to do via the API? If so it's better suited over at the
|
||||||
API? If so it's better suited over at the
|
[Lastenheft](https://gitlab.com/fabinfra/fabaccess_lastenheft) because that's where the required coordination for that will end up happening
|
||||||
[Lastenheft](https://gitlab.com/fabinfra/fabaccess_lastenheft) because that's where the required
|
2. Who else needs that feature? Is this something super specific to your environment/application or something that others will want too? If it's something that's relevant for more people please also tell us that in the feature request.
|
||||||
coordination for that will end up happening
|
3. Can you already get partway or all the way there using what's there already? If so please also tell us what you're currently doing and what doesn't work or why you dislike your current solution.
|
||||||
2. Who else needs that feature? Is this something super specific to your environment/application or
|
|
||||||
something that others will want too? If it's something that's relevant for more people please
|
|
||||||
also tell us that in the feature request.
|
|
||||||
3. Can you already get partway or all the way there using what's there already? If so please also
|
|
||||||
tell us what you're currently doing and what doesn't work or why you dislike your current
|
|
||||||
solution.
|
|
||||||
|
|
||||||
## Contributing Code
|
## Contributing Code
|
||||||
|
|
||||||
To help develop Difluoroborane you will need a Rust toolchain. I heavily recommend installing
|
To help develop Difluoroborane you will need a Rust toolchain. We heavily recommend installing [rustup](https://rustup.rs) even if your distribution provides a recent enough rustc, simply because it allows to easily switch compilers between several versions of both stable and nightly. It also allows you to download the respective stdlib crate, giving you the option of an offline reference.
|
||||||
[rustup](https://rustup.rs) even if your distribution provides a recent enough rustc, simply because
|
|
||||||
it allows to easily switch compilers between several versions of both stable and nightly. It also
|
|
||||||
allows you to download the respective stdlib crate, giving you the option of an offline reference.
|
|
||||||
|
|
||||||
We use a stable release branch / moving development workflow. This means that all *new* development
|
We use a stable release branch / moving development workflow. This means that all *new* development should happen on the `development` branch which is regularly merged into `stable` as releases. The exception of course are bug- and hotfixes that can target whichever branch.
|
||||||
should happen on the `development` branch which is regularly merged into `stable` as releases. The
|
|
||||||
exception of course are bug- and hotfixes that can target whichever branch.
|
|
||||||
|
|
||||||
If you want to add a new feature please work off the development branch. We suggest you create
|
If you want to add a new feature please work off the development branch. We suggest you create yourself a feature branch, e.g. using
|
||||||
yourself a feature branch, e.g. using `git switch development; git checkout -b
|
|
||||||
feature/my-cool-feature`.
|
|
||||||
Using a feature branch keeps your local `development` branch clean, making it easier to later rebase
|
|
||||||
your feature branch onto it before you open a pull/merge request.
|
|
||||||
|
|
||||||
When you want feedback on your current progress or are ready to have it merged upstream open a merge
|
```git switch development; git checkout -b feature/my-cool-feature```
|
||||||
request. Don't worry we don't bite! ^^
|
|
||||||
|
|
||||||
|
Using a feature branch keeps your local `development` branch clean, making it easier to later rebase your feature branch onto it before you open a pull/merge request.
|
||||||
|
|
||||||
# Development Setup
|
When you want feedback on your current progress or are ready to have it merged upstream open a merge request. Don't worry, we don't bite! ^^
|
||||||
|
|
||||||
## Cross-compilation
|
|
||||||
|
|
||||||
If you want to cross-compile you need both a C-toolchain for your target
|
|
||||||
and install the Rust stdlib for said target.
|
|
||||||
|
|
||||||
As an example for the target `aarch64-unknown-linux-gnu` (64-bit ARMv8
|
|
||||||
running Linux with the glibc, e.g. a Raspberry Pi 3 or later with a 64-bit
|
|
||||||
Debian Linux installation):
|
|
||||||
|
|
||||||
1. Install C-toolchain using your distro package manager:
|
|
||||||
- On Archlinux: `pacman -S aarch64-unknown-linux-gnu-gcc`
|
|
||||||
2. Install the Rust stdlib:
|
|
||||||
- using rustup: `rustup target add aarch64-unknown-linux-gnu`
|
|
||||||
3. Configure your cargo config:
|
|
||||||
|
|
||||||
### Configuring cargo
|
|
||||||
|
|
||||||
You need to tell Cargo to use your C-toolchain. For this you need to have
|
|
||||||
a block in [your user cargo config](https://doc.rust-lang.org/cargo/reference/config.html) setting at
|
|
||||||
least the paths to the gcc as `linker` and ar as `ar`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[target.aarch64-unknown-linux-gnu]
|
|
||||||
# You must set the gcc as linker since a lot of magic must happen here.
|
|
||||||
linker = "aarch64-linux-gnu-gcc"
|
|
||||||
ar = "aarch64-linux-gnu-ar"
|
|
||||||
```
|
|
||||||
|
|
||||||
This block should be added to your **user** cargo config (usually
|
|
||||||
`~/.cargo/config.toml`), since these values can differ between distros and
|
|
||||||
users.
|
|
||||||
|
|
||||||
To actually compile for the given triple you need to call `cargo build`
|
|
||||||
with the `--target` flag:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cargo build --release --target=aarch64-unknown-linux-gnu
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Sadly, still very much `// TODO:`. We're working on it! :/
|
|
||||||
|
54
INSTALL.md
54
INSTALL.md
@ -1,54 +0,0 @@
|
|||||||
# Installation
|
|
||||||
|
|
||||||
Currently there are no distribution packages available.
|
|
||||||
However installation is reasonably straight-forward, since Difluoroborane compiles into a single
|
|
||||||
mostly static binary with few dependencies.
|
|
||||||
|
|
||||||
At the moment only Linux is supported. If you managed to compile Difluoroborane please open an issue
|
|
||||||
outlining your steps or add a merge request expanding this part. Thanks!
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
General requirements; scroll down for distribution-specific instructions
|
|
||||||
|
|
||||||
- GNU SASL (libgsasl).
|
|
||||||
* If you want to compile Difluoroborane from source you will potentially also need development
|
|
||||||
headers
|
|
||||||
- capnproto
|
|
||||||
- rustc stable / nightly >= 1.48
|
|
||||||
* If your distribution does not provide a recent enough rustc, [rustup](https://rustup.rs/) helps
|
|
||||||
installing a local toolchain and keeping it up to date.
|
|
||||||
|
|
||||||
###### Arch Linux:
|
|
||||||
```shell
|
|
||||||
$ pacman -S gsasl rust capnproto
|
|
||||||
```
|
|
||||||
|
|
||||||
## Compiling from source
|
|
||||||
|
|
||||||
Difluoroborane uses Cargo, so compilation boils down to:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo build --release
|
|
||||||
```
|
|
||||||
https://www.geeksforgeeks.org/how-to-install-rust-on-raspberry-pi/ can show you how to install rust on your Linux computer.
|
|
||||||
|
|
||||||
The compiled binary can then be found in `./target/release/bffhd`
|
|
||||||
|
|
||||||
### Cross-compiling
|
|
||||||
|
|
||||||
If you need to compile for a different CPU target than your own (e.g. you want
|
|
||||||
to use BFFH on a raspberry pi but compile on your desktop PC), you need to
|
|
||||||
setup a cross-compilation toolchain and configure your Cargo correctly.
|
|
||||||
[The `CONTRIBUTING.md` has a section on how to setup a cross-compilation system.](CONTRIBUTING.md#cross-compilation)
|
|
||||||
|
|
||||||
# Running bffhd
|
|
||||||
|
|
||||||
The server can be ran either using `cargo`, which will also compile the binary if necessary, or directly.
|
|
||||||
|
|
||||||
When running using `cargo` you need to pass arguments to bffh after a `--`, so
|
|
||||||
e.g. `cargo run --release -- --help` or `cargo run --release -- -c examples/bffh.toml`.
|
|
||||||
|
|
||||||
When running directly the `bffhd` binary can be copied anywhere.
|
|
||||||
|
|
||||||
A list of arguments for the server is found in the help, so `bffhd --help` or `cargo run --release -- --help`.
|
|
@ -20,7 +20,7 @@ be ported to as many platforms as possible.
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
See [INSTALL.md](INSTALL.md)
|
See [https://fab-access.org/install](https://fab-access.org/install)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 19f20f5154f0eced6288ff56cac840025ee51da1
|
Subproject commit f3f53dafb6b7d23a19947f2a32d4ed5ee4e91d22
|
@ -1,39 +0,0 @@
|
|||||||
strict digraph connection {
|
|
||||||
Establish [label="TCP/SCTP connection established"];
|
|
||||||
Closed [label="TCP/SCTP connection closed"];
|
|
||||||
Open;
|
|
||||||
SASL;
|
|
||||||
Authenticated;
|
|
||||||
STARTTLS;
|
|
||||||
Encrypted;
|
|
||||||
|
|
||||||
Establish -> Open [label=open];
|
|
||||||
|
|
||||||
Open -> Closed [label=close];
|
|
||||||
|
|
||||||
Open -> SASL [label=auth];
|
|
||||||
SASL -> SASL [label=step];
|
|
||||||
// Authentication fails
|
|
||||||
SASL -> Closed [label=fails];
|
|
||||||
// Authentication succeeds
|
|
||||||
SASL -> Authenticated [label=successful];
|
|
||||||
|
|
||||||
Open -> STARTTLS [label=starttls];
|
|
||||||
// TLS wrapping succeeds
|
|
||||||
STARTTLS -> Encrypted [label=successful];
|
|
||||||
// TLS wrapping fails
|
|
||||||
STARTTLS -> Closed [label=fails];
|
|
||||||
|
|
||||||
Authenticated -> SASL_TLS [label=starttls];
|
|
||||||
SASL_TLS -> Closed [label=fails];
|
|
||||||
SASL_TLS -> AuthEnc [label=successful];
|
|
||||||
|
|
||||||
Encrypted -> TLS_SASL [label=auth];
|
|
||||||
TLS_SASL -> TLS_SASL [label=step];
|
|
||||||
TLS_SASL -> Closed [label=fails];
|
|
||||||
TLS_SASL -> AuthEnc [label=successful];
|
|
||||||
|
|
||||||
// Only authenticated connections may open RPC. For "unauth", use the `Anonymous` SASL method.
|
|
||||||
AuthEnc -> RPC [label=bootstrap];
|
|
||||||
Authenticated -> RPC [label=bootstrap];
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
# Stream initiation
|
|
||||||
|
|
||||||
In a session there are two parties: The initiating entity and the receiving
|
|
||||||
entity. This terminology does not refer to information flow but rather to the
|
|
||||||
side opening a connection respectively the one listening for connection
|
|
||||||
attempts.
|
|
||||||
In the currently envisioned use-case the initiating entity is a) a client
|
|
||||||
(i.e. interactive or batch/automated program) trying to interact in some way or
|
|
||||||
other with a server b) a server trying to exchange / request information
|
|
||||||
with/from another server (i.e. federating). The receiving entity however is
|
|
||||||
already a server.
|
|
||||||
|
|
||||||
Additionally the amount and type of clients is likely to be more diverse and
|
|
||||||
less up to date than the servers.
|
|
||||||
Conclusions I draw from this:
|
|
||||||
- Clients are more likely to implement an outdated version of the communication
|
|
||||||
protocol.
|
|
||||||
- The place for backwards-compatability should be the servers.
|
|
||||||
- Thus the client (initiating entity) should send the expected API version
|
|
||||||
first, the server then using that as a basis to decide with which API
|
|
||||||
version to answer.
|
|
||||||
|
|
||||||
# Stream negotiation
|
|
||||||
|
|
||||||
Since the receiving entity for a connection is responsible for the machines it
|
|
||||||
controls it imposes conditions for connecting either as client or as federating
|
|
||||||
server. At least every initiating entity is required to authenticate itself to
|
|
||||||
the receiving entity before attempting further actions or requesting
|
|
||||||
information. But a receiving entity can require other features, such as
|
|
||||||
transport layer encryption.
|
|
||||||
To this end a receiving entity informs the initiating entity about features that
|
|
||||||
it requires from the initiating entity before taking any further action and
|
|
||||||
features that are voluntary to negotiate but may improve qualities of the stream
|
|
||||||
(such as message compression)
|
|
||||||
|
|
||||||
A varying set of conditions implies negotiation needs to take place. Since
|
|
||||||
features potentially require a strict order (e.g. Encryption before
|
|
||||||
Authentication) negotiation has to be a multi-stage process. Further
|
|
||||||
restrictions are imposed because some features may only be offered after others
|
|
||||||
have been established (e.g. SASL authentication only becoming available after
|
|
||||||
encryption, EXTERNAL mechanism only being available to local sockets or
|
|
||||||
connections providing a certificate)
|
|
@ -1,93 +0,0 @@
|
|||||||
strict digraph state {
|
|
||||||
rank = 0
|
|
||||||
subgraph "cluster_internal_state" {
|
|
||||||
rank = 1
|
|
||||||
ctr = applied
|
|
||||||
start
|
|
||||||
[shape=doublecircle, label="BFFH"]
|
|
||||||
created
|
|
||||||
[label="Machine object created"];
|
|
||||||
start -> created;
|
|
||||||
|
|
||||||
created -> attach
|
|
||||||
[label="New state or loaded from disk"];
|
|
||||||
|
|
||||||
attach
|
|
||||||
[label="Attach actor", shape=box];
|
|
||||||
|
|
||||||
unapplied
|
|
||||||
[label="Unapplied"];
|
|
||||||
applied
|
|
||||||
[label="Applied"];
|
|
||||||
verified
|
|
||||||
[label="Verified"];
|
|
||||||
|
|
||||||
wait_apply
|
|
||||||
[label="Wait ∀ Actors", shape=box]
|
|
||||||
wait_verify
|
|
||||||
[label="Wait ∀ Actors", shape=box]
|
|
||||||
|
|
||||||
unapplied -> wait_apply -> applied;
|
|
||||||
applied -> wait_verify -> verified;
|
|
||||||
|
|
||||||
applied -> unapplied
|
|
||||||
[label="statechange received"];
|
|
||||||
verified -> unapplied
|
|
||||||
[label="statechange received"];
|
|
||||||
unapplied -> unapplied
|
|
||||||
[label="statechange received"];
|
|
||||||
|
|
||||||
unapplied -> attach -> unapplied;
|
|
||||||
applied -> attach -> unapplied;
|
|
||||||
verified -> attach -> unapplied;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
subgraph "cluster_actor" {
|
|
||||||
rank = 1
|
|
||||||
center = actor_applied
|
|
||||||
actor_start
|
|
||||||
[shape=doublecircle, label="Actor"];
|
|
||||||
actor_fresh
|
|
||||||
[label="Actor was just constructed"];
|
|
||||||
actor_start -> actor_fresh;
|
|
||||||
|
|
||||||
actor_attached
|
|
||||||
[label="Attached"];
|
|
||||||
actor_unapplied
|
|
||||||
[label="Unapplied"];
|
|
||||||
actor_applied
|
|
||||||
[label="Applied"];
|
|
||||||
actor_verified
|
|
||||||
[label="Verified"];
|
|
||||||
|
|
||||||
wait_initial
|
|
||||||
[label="Recv", shape=box];
|
|
||||||
wait_state
|
|
||||||
[label="Recv", shape=box];
|
|
||||||
|
|
||||||
actor_fresh -> wait_initial -> actor_attached;
|
|
||||||
|
|
||||||
actor_attached -> actor_applied
|
|
||||||
[label="initialize/apply"];
|
|
||||||
actor_unapplied -> actor_applied
|
|
||||||
[label="apply"];
|
|
||||||
actor_applied -> actor_verified
|
|
||||||
[label="verify"];
|
|
||||||
|
|
||||||
actor_unapplied -> wait_state;
|
|
||||||
actor_applied -> wait_state;
|
|
||||||
actor_verified -> wait_state;
|
|
||||||
|
|
||||||
wait_state -> actor_unapplied;
|
|
||||||
}
|
|
||||||
|
|
||||||
attach -> wait_initial
|
|
||||||
[label="Send initial state to that actor", style=dotted]
|
|
||||||
unapplied -> wait_state
|
|
||||||
[label="Send new state to all actors", style=dotted];
|
|
||||||
actor_applied -> wait_apply
|
|
||||||
[label="Confirm apply", style=dotted];
|
|
||||||
actor_verified -> wait_verify
|
|
||||||
[label="Confirm verify", style=dotted];
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
# API-Testsetup
|
|
||||||
|
|
||||||
wirklich nur um das API zu testen. ATM implementiert: machines::* & machine::read, authenticate
|
|
||||||
|
|
||||||
1. Ein mosquitto o.ä MQTT Server starten
|
|
||||||
1. Datenbanken füllen: `cargo run -- -c examples/bffh.dhall --load=examples`
|
|
||||||
1. Daemon starten: `cargo run -- -c examples/bffh.dhall`
|
|
||||||
1. ???
|
|
||||||
1. PROFIT!
|
|
||||||
|
|
||||||
A dockerized version of this example can be found in the docker subdirectory
|
|
@ -1,179 +0,0 @@
|
|||||||
#!/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)
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
echo "Bash actor called with $@" > /tmp/act
|
|
||||||
echo "Bash actor called with: $@"
|
|
@ -1,237 +0,0 @@
|
|||||||
{- Main configuration file for bffh
|
|
||||||
- ================================
|
|
||||||
-
|
|
||||||
- In this configuration file you configure almost all parts of how bffh operates, but most importantly:
|
|
||||||
- * Machines
|
|
||||||
- * Initiators and Actors
|
|
||||||
- * Which Initiators and Actors relate to which machine(s)
|
|
||||||
- * Roles and the permissions granted by them
|
|
||||||
-}
|
|
||||||
|
|
||||||
-- The config is in the configuration format/language dhall. You can find more information about dhall over at
|
|
||||||
-- https://dhall-lang.org
|
|
||||||
|
|
||||||
-- (Our) Dhall is somewhat similar to JSON and YAML in that it expects a top-level object containing the
|
|
||||||
-- configuration values
|
|
||||||
{
|
|
||||||
-- Configure the addresses and ports bffh listens on
|
|
||||||
listens = [
|
|
||||||
-- BFFH binds a port for every listen object in this array.
|
|
||||||
-- Each listen object is of the format { address = <STRING>, port = <INTEGER> }
|
|
||||||
-- If you don't specify a port bffh will use the default of `59661`
|
|
||||||
-- 'address' can be a IP address or a hostname
|
|
||||||
-- If bffh can not bind a port for the specified combination if will log an error but *continue with the remaining ports*
|
|
||||||
{ address = "127.0.0.1", port = 59661 },
|
|
||||||
{ address = "::1", port = 59661 },
|
|
||||||
{ address = "steak.fritz.box", port = 59661 }
|
|
||||||
],
|
|
||||||
|
|
||||||
-- Configure TLS. BFFH requires a PEM-encoded certificate and the associated key as two separate files
|
|
||||||
certfile = "examples/self-signed-cert.pem",
|
|
||||||
keyfile = "examples/self-signed-key.pem",
|
|
||||||
|
|
||||||
-- BFFH right now requires a running MQTT broker.
|
|
||||||
mqtt_url = "tcp://localhost:1883",
|
|
||||||
|
|
||||||
-- Path to the database file for bffh. bffh will in fact create two files; ${db_path} and ${db_path}.lock.
|
|
||||||
-- BFFH will *not* create any directories so ensure that the directory exists and the user running bffh has write
|
|
||||||
-- 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 = {
|
|
||||||
-- Role definitions
|
|
||||||
-- A role definition is of the form
|
|
||||||
-- rolename = {
|
|
||||||
-- parents = [<list of role names to inherit from>],
|
|
||||||
-- permissions = [<list of perm rules>],
|
|
||||||
-- }
|
|
||||||
--
|
|
||||||
-- Role names are case sensitive, so RoleName != rolename.
|
|
||||||
--
|
|
||||||
-- If you want either parents or permissions to be empty its best to completely skip it:
|
|
||||||
testrole = {
|
|
||||||
permissions = [ "lab.some.admin" ]
|
|
||||||
},
|
|
||||||
somerole = {
|
|
||||||
parents = ["testparent"],
|
|
||||||
-- "Permissions" are formatted as Perm Rules, so you can use the wildcards '*' and '+'
|
|
||||||
permissions = [ "lab.test.*" ]
|
|
||||||
},
|
|
||||||
-- Roles can inherit from each other. In that case a member of e.g. 'somerole' that inherits from
|
|
||||||
-- 'testparent' will have all the permissions of 'somerole' AND 'testparent' assigned to them.
|
|
||||||
-- Right now permissions are stricly additive so you can't take a permission away in a child role that a parent
|
|
||||||
-- role grants.
|
|
||||||
testparent = {
|
|
||||||
permissions = [
|
|
||||||
"lab.some.write",
|
|
||||||
"lab.some.read",
|
|
||||||
"lab.some.disclose"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
-- Configure machines
|
|
||||||
-- "Machines" (which in future will be more appropiately named "resources") are the main thing bffh is concerned
|
|
||||||
-- with.
|
|
||||||
-- You can define an almost limitless amount of machines (well 2^64 - 1, so 18_446_744_073_709_551_615 to be precise)
|
|
||||||
-- Each of these machines can then have several "actors" and "initiators" assigned
|
|
||||||
machines = {
|
|
||||||
Testmachine = {
|
|
||||||
-- A machine comes with two "names". The id above ("Testmachine") and the "name" ("MachineA").
|
|
||||||
-- The id is what you'll use in the config format and is strictly limited to alphanumeric characters and '_'
|
|
||||||
-- and must begin with a letter. Most importantly you CAN NOT use '-' or spaces in an identifier
|
|
||||||
-- (dhall makes this technically possible but you can break things in subtle ways)
|
|
||||||
|
|
||||||
-- REQUIRED. The "name" of a machine is what will be presented to humans. It can contain all unicode
|
|
||||||
-- including spaces and nonprintable characters.
|
|
||||||
-- A name SHOULD be short but unique.
|
|
||||||
name = "MachineA",
|
|
||||||
|
|
||||||
-- OPTIONAL. A description can be assigned to machines. It will also only be shown to humans. Thus it is
|
|
||||||
-- once again limited only to unicode. If you want to provide your users with important additional
|
|
||||||
-- information other than the name this is the place to do it.
|
|
||||||
description = "A test machine",
|
|
||||||
|
|
||||||
-- OPTIONAL. If you have a wiki going into more detail how to use a certain machine or what to keep in
|
|
||||||
-- mind when using it you can provide a URL here that will be presented to users.
|
|
||||||
wiki = "https://wiki.example.org/machineA",
|
|
||||||
|
|
||||||
-- OPTIONAL. You can assign categories to machines to allow clients to group/filter machines by them.
|
|
||||||
category = "Testcategory",
|
|
||||||
|
|
||||||
-- REQUIRED.
|
|
||||||
-- Each machine MUST have *all* Permission levels assigned to it.
|
|
||||||
-- Permissions aren't PermRules as used in the 'roles' definitions but must be precise without wildcards.
|
|
||||||
-- Permission levels aren't additive, so a user having 'manage' permission does not automatically get
|
|
||||||
-- 'read' or 'write' permission.
|
|
||||||
|
|
||||||
-- (Note, disclose is not fully implemented at the moment)
|
|
||||||
-- Users lacking 'disclose' will not be informed about this machine in any way and it will be hidden from
|
|
||||||
-- them in the client. Usually the best idea is to assign 'read' and 'disclose' to the same permission.
|
|
||||||
disclose = "lab.test.read",
|
|
||||||
|
|
||||||
-- Users lacking 'read' will be shown a machine including name, description, category and wiki but not
|
|
||||||
-- it's current state. The current user is not disclosed.
|
|
||||||
read = "lab.test.read",
|
|
||||||
|
|
||||||
-- The 'write' permission allows to 'use' the machine.
|
|
||||||
write = "lab.test.write",
|
|
||||||
|
|
||||||
-- Manage represents the 'superuser' permission. Users with this permission can force set any state and
|
|
||||||
-- read out the current user
|
|
||||||
manage = "lab.test.admin"
|
|
||||||
},
|
|
||||||
Another = {
|
|
||||||
wiki = "test_another",
|
|
||||||
category = "test",
|
|
||||||
disclose = "lab.test.read",
|
|
||||||
manage = "lab.test.admin",
|
|
||||||
name = "Another",
|
|
||||||
read = "lab.test.read",
|
|
||||||
write = "lab.test.write"
|
|
||||||
},
|
|
||||||
Yetmore = {
|
|
||||||
description = "Yet more test machines",
|
|
||||||
disclose = "lab.test.read",
|
|
||||||
manage = "lab.test.admin",
|
|
||||||
name = "Yetmore",
|
|
||||||
read = "lab.test.read",
|
|
||||||
write = "lab.test.write"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
-- Actor configuration. Actors are how bffh affects change in the real world by e.g. switching a power socket
|
|
||||||
-- using a shelly
|
|
||||||
actors = {
|
|
||||||
-- Actors similarly to machines have an 'id'. This id (here "Shelly1234") is limited to Alphanumeric ASCII
|
|
||||||
-- and must begin with a letter.
|
|
||||||
Shelly1234 = {
|
|
||||||
-- Actors are modular pieces of code that are loaded as required. The "Shelly" module will send
|
|
||||||
-- activation signals to a shelly switched power socket over MQTT
|
|
||||||
module = "Shelly",
|
|
||||||
-- Actors can have arbitrary parameters passed to them, varying by actor module.
|
|
||||||
params = {
|
|
||||||
-- For Shelly you can configure the MQTT topic segment it uses. Shellies listen to a specific topic
|
|
||||||
-- containing their name (which is usually of the form "shelly_<id>" but can be changed).
|
|
||||||
-- If you do not configure a topic here the actor will use it's 'id' (in this case "Shelly1234").
|
|
||||||
topic = "Topic1234"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Bash = {
|
|
||||||
-- The "Process" module runs a given script or command on state change.
|
|
||||||
-- bffh invoces the given cmd as `$ ${cmd} ${args} ${id} ${state}` so e.g. as
|
|
||||||
-- `$ ./examples/actor.sh your ad could be here Bash inuse`
|
|
||||||
module = "Process",
|
|
||||||
params = {
|
|
||||||
-- which is configured by the (required) 'cmd' parameter. Paths are relative to PWD of bffh. Systemd
|
|
||||||
-- and similar process managers may change this PWD so it's usually the most future-proof to use
|
|
||||||
-- absolute paths.
|
|
||||||
cmd = "./examples/actor.sh",
|
|
||||||
-- You can pass static args in here, these will be passed to every invocation of the command by this actor.
|
|
||||||
-- args passed here are split by whitespace, so these here will be passed as 5 separate arguments
|
|
||||||
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" }}
|
|
||||||
},
|
|
||||||
|
|
||||||
-- Linkng up machines to actors
|
|
||||||
-- Actors need to be connected to machines to be useful. A machine can be connected to multiple actors, but one
|
|
||||||
-- actor can only be connected to one machine.
|
|
||||||
actor_connections = [
|
|
||||||
{ machine = "Testmachine", actor = "Shelly1234" },
|
|
||||||
{ machine = "Another", actor = "Bash" },
|
|
||||||
{ machine = "Yetmore", actor = "Bash2" },
|
|
||||||
{ machine = "Yetmore", actor = "FailBash"}
|
|
||||||
],
|
|
||||||
|
|
||||||
-- Initiators are configured almost the same way as Actors, refer to actor documentation for more details
|
|
||||||
-- The below '{=}' is what you need if you want to define *no* initiators at all and only use the API with apps
|
|
||||||
-- to let people use machines.
|
|
||||||
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.
|
|
||||||
--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" }]
|
|
||||||
|
|
||||||
instanceurl = "https://example.com",
|
|
||||||
spacename = "examplespace"
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
# API-Testsetup, aber mit Docker
|
|
||||||
|
|
||||||
wirklich nur um das API zu testen. ATM implementiert: machines::* & machine::read, authenticate
|
|
||||||
|
|
||||||
* run `docker-compose up` in this directory
|
|
@ -1,42 +0,0 @@
|
|||||||
-- { actor_connections = [] : List { _1 : Text, _2 : Text }
|
|
||||||
{ actor_connections = [{ _1 = "Testmachine", _2 = "Actor" }]
|
|
||||||
, actors =
|
|
||||||
{ Actor = { module = "Shelly", params = {=} }
|
|
||||||
}
|
|
||||||
, init_connections = [] : List { _1 : Text, _2 : Text }
|
|
||||||
--, init_connections = [{ _1 = "Initiator", _2 = "Testmachine" }]
|
|
||||||
, initiators =
|
|
||||||
{ Initiator = { module = "Dummy", params = {=} }
|
|
||||||
}
|
|
||||||
, listens =
|
|
||||||
[ { address = "::", port = Some 59661 }
|
|
||||||
]
|
|
||||||
, machines =
|
|
||||||
{ Testmachine =
|
|
||||||
{ description = Some "A test machine"
|
|
||||||
, disclose = "lab.test.read"
|
|
||||||
, manage = "lab.test.admin"
|
|
||||||
, name = "Testmachine"
|
|
||||||
, read = "lab.test.read"
|
|
||||||
, write = "lab.test.write"
|
|
||||||
},
|
|
||||||
Another =
|
|
||||||
{ description = Some "Another test machine"
|
|
||||||
, disclose = "lab.test.read"
|
|
||||||
, manage = "lab.test.admin"
|
|
||||||
, name = "Another"
|
|
||||||
, read = "lab.test.read"
|
|
||||||
, write = "lab.test.write"
|
|
||||||
},
|
|
||||||
Yetmore =
|
|
||||||
{ description = Some "Yet more test machines"
|
|
||||||
, disclose = "lab.test.read"
|
|
||||||
, manage = "lab.test.admin"
|
|
||||||
, name = "Yetmore"
|
|
||||||
, read = "lab.test.read"
|
|
||||||
, write = "lab.test.write"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
, mqtt_url = "tcp://mqtt:1883"
|
|
||||||
, db_path = "/tmp/bffh"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
Testuser = "secret"
|
|
@ -1,19 +0,0 @@
|
|||||||
[anotherrole]
|
|
||||||
|
|
||||||
[testrole]
|
|
||||||
permissions = [
|
|
||||||
"lab.test.*"
|
|
||||||
]
|
|
||||||
|
|
||||||
[somerole]
|
|
||||||
parents = ["testparent/lmdb"]
|
|
||||||
permissions = [
|
|
||||||
"lab.some.admin"
|
|
||||||
]
|
|
||||||
|
|
||||||
[testparent]
|
|
||||||
permissions = [
|
|
||||||
"lab.some.write",
|
|
||||||
"lab.some.read",
|
|
||||||
"lab.some.disclose",
|
|
||||||
]
|
|
@ -1,11 +0,0 @@
|
|||||||
[Testuser]
|
|
||||||
# Define them in roles.toml as well
|
|
||||||
roles = ["somerole/lmdb", "testrole/lmdb"]
|
|
||||||
|
|
||||||
# If two or more users want to use the same machine at once the higher prio
|
|
||||||
# wins
|
|
||||||
priority = 0
|
|
||||||
|
|
||||||
# You can add whatever random data you want.
|
|
||||||
# It will get stored in the `kv` field in UserData.
|
|
||||||
noot = "noot!"
|
|
@ -1,13 +0,0 @@
|
|||||||
version: "3.8"
|
|
||||||
services:
|
|
||||||
bffh:
|
|
||||||
image: registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest
|
|
||||||
ports:
|
|
||||||
- "59661:59661"
|
|
||||||
volumes:
|
|
||||||
# generate a sample config.toml by running "docker run registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest --print-default > examples/config.toml" from the project root. You may have to delete the ipv6 listen section.
|
|
||||||
- "./config:/etc/bffh"
|
|
||||||
links:
|
|
||||||
- mqtt
|
|
||||||
mqtt:
|
|
||||||
image: eclipse-mosquitto:1.6.13
|
|
@ -1,11 +0,0 @@
|
|||||||
# Integration tests with Docker
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
* spawns 2 instances of our bffh container and required mqqt broker
|
|
||||||
* spawns an additional debian to run a shell
|
|
||||||
* the containers can reach each other by their hostname
|
|
||||||
|
|
||||||
## How to start
|
|
||||||
|
|
||||||
* run `docker-compose up --exit-code-from test-manager` in this directory
|
|
||||||
* this will kill all containers when
|
|
@ -1,20 +0,0 @@
|
|||||||
{ actor_connections = [{ _1 = "Testmachine", _2 = "Actor" }]
|
|
||||||
, actors =
|
|
||||||
{ Actor = { module = "Shelly", params = {=} }
|
|
||||||
}
|
|
||||||
, init_connections = [{ _1 = "Initiator", _2 = "Testmachine" }]
|
|
||||||
, initiators =
|
|
||||||
{ Initiator = { module = "Dummy", params = {=} }
|
|
||||||
}
|
|
||||||
, listens = [{ address = "::", port = Some 59661 }]
|
|
||||||
, machines =
|
|
||||||
{ Testmachine =
|
|
||||||
{ description = Some "A test machine"
|
|
||||||
, disclose = "lab.test.read"
|
|
||||||
, manage = "lab.test.admin"
|
|
||||||
, name = "Testmachine"
|
|
||||||
, read = "lab.test.read"
|
|
||||||
, write = "lab.test.write"
|
|
||||||
} }
|
|
||||||
, mqtt_url = "tcp://mqtt-a:1883"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
Testuser = "secret"
|
|
@ -1,20 +0,0 @@
|
|||||||
[testrole]
|
|
||||||
name = "Testrole"
|
|
||||||
permissions = [
|
|
||||||
"lab.test.*"
|
|
||||||
]
|
|
||||||
|
|
||||||
[somerole]
|
|
||||||
name = "Somerole"
|
|
||||||
parents = ["testparent%lmdb"]
|
|
||||||
permissions = [
|
|
||||||
"lab.some.admin"
|
|
||||||
]
|
|
||||||
|
|
||||||
[testparent]
|
|
||||||
name = "Testparent"
|
|
||||||
permissions = [
|
|
||||||
"lab.some.write",
|
|
||||||
"lab.some.read",
|
|
||||||
"lab.some.disclose",
|
|
||||||
]
|
|
@ -1,11 +0,0 @@
|
|||||||
[Testuser]
|
|
||||||
# Define them in roles.toml as well
|
|
||||||
roles = []
|
|
||||||
|
|
||||||
# If two or more users want to use the same machine at once the higher prio
|
|
||||||
# wins
|
|
||||||
priority = 0
|
|
||||||
|
|
||||||
# You can add whatever random data you want.
|
|
||||||
# It will get stored in the `kv` field in UserData.
|
|
||||||
noot = "noot!"
|
|
@ -1,20 +0,0 @@
|
|||||||
{ actor_connections = [{ _1 = "Testmachine", _2 = "Actor" }]
|
|
||||||
, actors =
|
|
||||||
{ Actor = { module = "Shelly", params = {=} }
|
|
||||||
}
|
|
||||||
, init_connections = [{ _1 = "Initiator", _2 = "Testmachine" }]
|
|
||||||
, initiators =
|
|
||||||
{ Initiator = { module = "Dummy", params = {=} }
|
|
||||||
}
|
|
||||||
, listens = [{ address = "::", port = Some 59661 }]
|
|
||||||
, machines =
|
|
||||||
{ Testmachine =
|
|
||||||
{ description = Some "A test machine"
|
|
||||||
, disclose = "lab.test.read"
|
|
||||||
, manage = "lab.test.admin"
|
|
||||||
, name = "Testmachine"
|
|
||||||
, read = "lab.test.read"
|
|
||||||
, write = "lab.test.write"
|
|
||||||
} }
|
|
||||||
, mqtt_url = "tcp://mqtt-b:1883"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
Testuser = "secret"
|
|
@ -1,20 +0,0 @@
|
|||||||
[testrole]
|
|
||||||
name = "Testrole"
|
|
||||||
permissions = [
|
|
||||||
"lab.test.*"
|
|
||||||
]
|
|
||||||
|
|
||||||
[somerole]
|
|
||||||
name = "Somerole"
|
|
||||||
parents = ["testparent%lmdb"]
|
|
||||||
permissions = [
|
|
||||||
"lab.some.admin"
|
|
||||||
]
|
|
||||||
|
|
||||||
[testparent]
|
|
||||||
name = "Testparent"
|
|
||||||
permissions = [
|
|
||||||
"lab.some.write",
|
|
||||||
"lab.some.read",
|
|
||||||
"lab.some.disclose",
|
|
||||||
]
|
|
@ -1,11 +0,0 @@
|
|||||||
[Testuser]
|
|
||||||
# Define them in roles.toml as well
|
|
||||||
roles = []
|
|
||||||
|
|
||||||
# If two or more users want to use the same machine at once the higher prio
|
|
||||||
# wins
|
|
||||||
priority = 0
|
|
||||||
|
|
||||||
# You can add whatever random data you want.
|
|
||||||
# It will get stored in the `kv` field in UserData.
|
|
||||||
noot = "noot!"
|
|
@ -1,26 +0,0 @@
|
|||||||
version: "3.8"
|
|
||||||
services:
|
|
||||||
bffh-a:
|
|
||||||
image: registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest
|
|
||||||
command: ["sh", "-c", "difluoroborane -c /etc/bffh/bffh.dhall --load=/etc/bffh; difluoroborane -c /etc/bffh/bffh.dhall"]
|
|
||||||
volumes:
|
|
||||||
# generate a sample config.toml by running "docker run registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest --print-default > examples/config.toml" from the project root. You may have to delete the ipv6 listen section.
|
|
||||||
- "./config_a:/etc/bffh"
|
|
||||||
links:
|
|
||||||
- mqtt-a
|
|
||||||
mqtt-a:
|
|
||||||
image: eclipse-mosquitto
|
|
||||||
bffh-b:
|
|
||||||
image: registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest
|
|
||||||
command: ["sh", "-c", "difluoroborane -c /etc/bffh/bffh.dhall --load=/etc/bffh; difluoroborane -c /etc/bffh/bffh.dhall"]
|
|
||||||
volumes:
|
|
||||||
# generate a sample config.toml by running "docker run registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest --print-default > examples/config.toml" from the project root. You may have to delete the ipv6 listen section.
|
|
||||||
- "./config_b:/etc/bffh"
|
|
||||||
links:
|
|
||||||
- mqtt-b
|
|
||||||
mqtt-b:
|
|
||||||
image: eclipse-mosquitto
|
|
||||||
|
|
||||||
test-manager:
|
|
||||||
image: debian
|
|
||||||
tty: true
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
echo "This is some error output" > /dev/stderr
|
|
||||||
exit 115
|
|
@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
while True:
|
|
||||||
print('{ "state": { "1.3.6.1.4.1.48398.612.2.4": { "state": "Free" } } }')
|
|
||||||
sys.stdout.flush()
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
print('{ "state": { "1.3.6.1.4.1.48398.612.2.4": { "state": { "InUse": { "id": "Testuser" } } } } }')
|
|
||||||
sys.stdout.flush()
|
|
||||||
time.sleep(2)
|
|
@ -1,19 +0,0 @@
|
|||||||
-----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-----
|
|
@ -1,28 +0,0 @@
|
|||||||
-----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-----
|
|
@ -1,16 +0,0 @@
|
|||||||
[Testuser]
|
|
||||||
# These roles have to be defined in 'bffh.dhall'.
|
|
||||||
# Non-existant roles will not crash the server but print a `WARN` level message in the
|
|
||||||
# server log in the form "Did not find role somerole/internal while trying to tally".
|
|
||||||
roles = ["somerole", "testrole"]
|
|
||||||
|
|
||||||
# The password will be hashed using argon2id on load time and is not available in plaintext afterwards.
|
|
||||||
passwd = "secret"
|
|
||||||
|
|
||||||
# You can add whatever random data you want.
|
|
||||||
# It will get stored in the `kv` field in UserData.
|
|
||||||
# This is not used for anything at the moment
|
|
||||||
noot = "noot!"
|
|
||||||
|
|
||||||
# Store the card specific AES key in kv userdata
|
|
||||||
cardkey = "7ab8704a61b5317e1fe4cae9e3e1fd8d"
|
|
@ -1,8 +0,0 @@
|
|||||||
[UniqueUser]
|
|
||||||
roles = ["foorole", "barrole"]
|
|
||||||
|
|
||||||
[DuplicateUser]
|
|
||||||
roles = ["somerole"]
|
|
||||||
|
|
||||||
[DuplicateUser]
|
|
||||||
roles = ["different", "roles"]
|
|
Loading…
x
Reference in New Issue
Block a user