An open API service indexing awesome lists of open source software.

https://github.com/pingbird/tangent

Discord bot with a secure, interactive virtual machine
https://github.com/pingbird/tangent

Last synced: 9 months ago
JSON representation

Discord bot with a secure, interactive virtual machine

Awesome Lists containing this project

README

          

![](https://i.tst.sh/9gQQ5.png)

### Tangent - A discord bot with access to a full Linux VM

## How it works
Tangent uses [libvirt](https://libvirt.org/) to manage a qemu controlled Debian 9 virtual machine and communicates to it through a custom json rpc like protocol.

`tangent-server` contains the server that runs as an unprivelaged user on the VM, allowing the bot on the host machine to start processes, read stdin/stdout, and access files safely.

In it's current configuration the VM is on a closed virtual network with only the host machine being routable (`192.168.69.1`), iptables are set up so requests from the VM to the host are blocked to prevent it from attempting to connect to SSH or other services it should not have access to.

The only way for information to go in and out of the VM is through connections initiated by the host.

System resources are also heavily limited with 1 thread, 256MB of memory, and a 16GB virtual disk.

If you manage to put the VM in an unusable state for example by killing the server process, Tangent will automatically use virsh to reboot the VM which only takes around 4 seconds.

As a last resort if someone obtains root and bricks the system a qcow2 snapshot can restore the system state to brand new using the `qclean` command.

The bot itself is a Dart application and is designed to be as fault tolerant as possible, all buffers that the vm send to are capped, any malformed packets will instantly terminate the connection, and all of the async wrappers for files and processes are destroyed properly when closed.

## Usage

### Prefixes
Currently there are 3 command prefixes for convenience:
`.`, `α`, `@Tangent` (Will have per-server configuration later)

Any of these prefixes can be used to execute commands

### Misc commands
`purge ` - Purges a number of messages *(admin only)*

### Managment
`qstart` - Start the VM *(trusted only)*\
`qrestart` - Restart the VM *(trusted only)*\
`qclean` - Revert the VM state to a clean snapshot *(trusted only)*

### Upload / Download
`upload [file/dir]` - Upload an attachment to the VM at the specified directory or file name, defaults to the home directory\
`download ` - Download a specific file from the VM to Discord

### Languages
Language commands support discord's code block formatting, for example:
````
lua ```lua
print("Hello, World!")
```
````
will interpret the contents of the code block.

You can provide compiler arguments and program arguments by putting text before and after the code block:
````
.c -ldl ```c
#include
int main(int argc, char** argv) {
printf("Hello\n");
for (int i = 0; i < argc; i++) {
printf("%i: %s\n", i, argv[i]);
}
}
```
extra arguments
````
Outputs:
```
Hello
0: ./tangent
1: extra
2: arguments
```

The bot is interactive, if you edit your message with a command it will re-run your command and update it's message.
When a user enters a new command or edit a previous one it will kill the previous process to prevent anything from lingering.

#### Commands:

`sh ` - Standard /bin/sh

Example

```sh
echo Hello from /bin/sh
```

`bash ` - Standard /bin/bash

Example

```sh
echo Hello from /bin/bash
```

`arm ` - ARM Assembly

Example

```arm
.globl main
main:
stmfd sp!, {lr}
ldr r0, =hello_text
bl puts
mov r0, #0
ldmfd sp!, {lr}
bx lr
hello_text:
.string "Hello from ARM\n"
```

`x86 ` - x86_64 Assembly

Example

```asm
.intel_syntax noprefix
.globl main
main:
push rax
mov edi, offset hello_text
xor eax, eax
call puts
xor eax, eax
pop rcx
ret
hello_text:
.string "Hello from x86\n"
```

`c ` - GCC 6.3.0

Example

```c
#include
int main() {
puts("Hello from C\n");
}
```

`cpp ` - G++ 6.3.0

Example

```cpp
#include
int main() {
std::cout << "Hello from C++\n";
}
```

`lua ` - Lua 5.3 Reference interpreter

`lua5.2 ` - Lua 5.2 Reference interpreter

`lua5.1 ` - Lua 5.1 Reference interpreter

`luajit ` - LuaJIT 2.0

Example

```lua
print("Hello from " .. _VERSION)
```

`py ` - Python 3

`py2 ` - Python 2

Example

```py
from platform import python_version
print('Hello from Python {}'.format(python_version()))
```

`js ` - Node.JS v4.8.2

Example

```js
console.log("Hello from Node.js " + process.version);
```

`pl ` - Perl

Example

```pl
print "Hello from Perl\n";
```

`java ` - OpenJDK 8

Example

```java
public class Tangent {
public static void main(String[] args) {
System.out.println("Hello from Java");
}
}
```

`lisp ` - SBCL

Example

```lisp
(format t "Hello from Lisp")
```

`bf ` - Brainfuck

Example

```bf
++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++.>+.+++++++..+++.<<++.>>---------.++++++++++++.---.--.<<.>------.>+++++.-----------------.++++++++.+++++.--------.+++++++++++++++.------------------.++++++++.
```

`cs ` - .NET Core C#

Example

```cs
class Program {
static void Main() {
System.Console.WriteLine("Hello from C#");
}
}
```

`fs ` - .NET Core F#

Example

```fs
[]
let main argv =
printfn "Hello from F#"
0
```

`haskell ` - GHC

Example

```hs
main = putStrLn "Hello from Haskell"
```

`php ` - PHP7

Example

```php

`cobol ` - OpenCOBOL

Example

```cob
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY 'Hello from COBOL'.
STOP RUN.
```

`go ` - Go 1.7.4

Example

```go
package main
import "fmt"
func main() {
fmt.Println("Hello from Go")
}
```

`ruby ` - Ruby 2.3.3

Example

```rb
puts 'Hello from Ruby'
```

`apl ` - GNU APL

Example

```apl
"Hello from APL"
```

`prolog ` - SWI Prolog

Example

```pl
:- initialization hello, halt.
hello :-
write('Hello from Prolog'), nl.
```

`ocaml ` - OCaml 4.02.3

Example

```ml
print_string "Hello from OCaml\n";;
```

`sml ` - SML-NJ v110.79

Example

```sml
print "Hello from SML\n";
```

`crystal ` - Crystal 0.28.0

Example

```cr
puts "Hello from Crystal"
```

`ada ` - GNAT

Example

```ada
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
begin
Put_Line ("Hello from Ada");
end Hello;
```

`d ` - GDC

Example

```d
import std.stdio;
void main() {
writeln("Hello from D");
}
```

`groovy ` - Groovy 2.4.8

Example

```groovy
println "Hello from Groovy"
```

`dart ` - Dart 2.3.1

Example

```dart
main() {
print("Hello from Dart");
}
```

`erlang ` - Erlang

Example

```erl
-module(tangent).
-export([main/0]).
main() -> io:fwrite("Hello from Erlang\n").
```

`forth ` - GNU FORTH

Example

```
.( Hello from FORTH) CR
```

`pascal ` - Free Pascal Compiler 3.0.0

Example

```pascal
program Tangent(output);
begin
writeln('Hello from Pascal');
end.
```

`hack ` - HipHop VM 4.8.0

Example

```hack
echo 'Hello from Hack';
```

`julia ` - Julia 0.4.7

Example

```julia
println("Hello from Julia")
```

`kotlin ` - Kotlin 1.3.31

Example

```kotlin
fun main(args : Array) {
println("Hello from Kotlin")
}
```

`scala ` - Scala 2.12.8

Example

```scala
object Tangent {
def main(args: Array[String]): Unit = {
println("Hello from Scala")
}
}
```

`swift ` - Swift 4.1

Example

```swift
import Swift
print("Hello from Swift")```
```

`typescript ` - Typescript 2.1.5 on Node.JS v4.8.2

Example

```ts
console.log("Hello from TypeScript");
```

`verilog ` - Icarus Verilog

Example

```v
module test;
initial begin
$display("Hello from Verilog");
end
endmodule
```

`wasm ` - Webassembly WAVM

Example

```scheme
(module
(import "env" "_fwrite" (func $__fwrite (param i32 i32 i32 i32) (result i32)))
(import "env" "_stdout" (global $stdoutPtr i32))
(import "env" "memory" (memory 1))
(export "main" (func $main))
(data (i32.const 8) "Hello from WASM\n")
(func (export "establishStackSpace") (param i32 i32) (nop))
(func $main (result i32)
(local $stdout i32)
(local.set $stdout (i32.load align=4 (global.get $stdoutPtr)))
(call $__fwrite
(i32.const 8)
(i32.const 1)
(i32.const 16)
(local.get $stdout)
)
(return (i32.const 0))
)
)
```

`scheme ` - MIT Scheme 9.1.1

Example

```scheme
(begin
(display "Hello from Scheme")
(newline))
```

`awk ` - GNU Awk 4.1.4

Example

```awk
BEGIN { print "Hello from AWK" }
```

`clojure ` - Clojure 1.8.0

Example

```clojure
(println "Hello from Clojure")
```

`tibasic ` - Limited TI-BASIC interpreter from [patrickfeltes/ti-basic-interpreter](https://github.com/patrickfeltes/ti-basic-interpreter/)

Example

```js
Disp "Hello from TI-BASIC"
```

`batch ` - WINE's cmd.exe

Example

```bat
@echo off
echo Hello from Batch
```

`racket ` - Racket 6.7

Example

```lisp
#lang racket/base
(print "Hello from Racket")
```

`Rust ` - rustc 1.24.1

Example

```rust
fn main() {
println!("Hello from Rust");
}
```

`bc ` - GNU Basic Calculator

Example

```lua
print "Hello from BC\n"
```

`ir ` - LLVM IR

Example

```
@.str = private unnamed_addr constant [20 x i8] c"Hello from LLVM IR\0A\00"

define i32 @main() #0 {
%1 = call i32 @puts(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str, i32 0, i32 0))
ret i32 0
}

declare i32 @puts(i8*) #1
```