blackmassgroup / v_exchange

A scalable web app features LiveView authentication, user roles and permission system, and secure S3/Wasabi uploads. It calculates file hashes with Erlang crypto library and uses Oban for all most API requests for automated retries.Has CI/CD setup and is deployed on Fly.io.
https://virus.exchange
82 stars 7 forks source link
ecto elixir elixir-phoenix exaws flyio phoenix phoenix-framework phoenix-liveview

VExchange

Features

Built With

Getting Started

Prerequisites

  1. Install erlang, Elixir, NodeJS, Postgres

    1. With homebrew the commands are:
    brew update
    brew install erlang elixir nodejs postgres
    1. Or if you prefer asdf
    brew update
    brew install asdf
    
    asdf plugin-add erlang
    asdf plugin-add elixir
    asdf plugin-add nodejs
    
    asdf install

Installation

  1. Clone this Repo and enter the directory.
  2. Set up the project with the command mix setup
  3. Set the following env variables in order to get Wasabi/S3 to work.
    1. AWS_ACCESS_KEY_ID
    2. AWS_SECRET_ACCESS_KEY
    3. S3_BUCKET_NAME
  4. Set the following env variables in order to get Triage / VT to work.
    1. VIRUS_TOTAL_API_KEY
    2. TRIAGE_API_KEY
  5. Set the following env variables in order to get Discord Logging to work. (optional)
    1. DISCORD_BOT_TOKEN
    2. DISCORD_CHANNEL_ID
  6. Start Phoenix server with iex -S mix phx.server
    1. Now you can visit localhost:4000 or localhost:4001 from your browser.
  7. Once you register a user, you make it admin by running this in the same window you ran iex -S mix phx.server in (yes we run commands in a running server)
    1. VExchange.Accounts.get_user!(1) |> VExchange.Accounts.add_role_to_user("Admin")

You can run unit tests with the command mix test

API Routes

Documentation can be found at here and requires an API key generated when a user signs up.

Example script using the upload API to upload all files from a sub directory.

import requests, os, sys
from concurrent.futures import ThreadPoolExecutor

MAX_WORKERS = 10
API_LOGIN = "https://virus.exchange/api/login"
API_UPLOAD = "https://virus.exchange/api/upload"

TOKEN=""
EMAIL="ur email"

if TOKEN == "":
        PASSWORD=input("Enter your password: ")
        r = requests.post(API_LOGIN, data={"email":EMAIL, "password":PASSWORD})
        TOKEN = r.json()["data"]["token"]

def process_file(subdir, file):
    filename = os.path.join(subdir, file)
    with open(filename, "rb+") as f:
        file_content = f.read()
        r = requests.post(API_UPLOAD, headers={'Authorization': f"Bearer {TOKEN}", "Content-Type": "application/x-www-form-urlencoded"}, data=file_content)
        print(f"{os.path.basename(filename)}: STATUS({r.status_code}) {r.text}")

def main(directory):
    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        for subdir, dirs, files in os.walk(directory):
            for file in files:
                executor.submit(process_file, subdir, file)

if __name__ == '__main__':
    main(sys.argv[1])

TODO

Database architecture 🗂

classDiagram
    class Sample{
      +Integer size
      +String md5
      +String sha1
      +String sha256
      +String sha512
      +String s3_object_key
      +Array names
      +Array tags
      +DateTime first_seen
    }

    class Users {
     +String email
     +String username
     +String password
     +Integer role_id
     +String hashed_password
     +DateTime confirmed_at
    }
    class Role {
        +String name
        +Jsonb permissions
    }