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
- Host: GitHub
- URL: https://github.com/pingbird/tangent
- Owner: pingbird
- Created: 2019-05-30T09:15:40.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2021-06-02T03:37:12.000Z (about 5 years ago)
- Last Synced: 2025-03-18T17:24:45.620Z (over 1 year ago)
- Language: Dart
- Homepage:
- Size: 124 KB
- Stars: 17
- Watchers: 0
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README

### 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
```