Compare commits

..

1 Commits

Author SHA1 Message Date
21e1bb2173 See if can build for linux
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-04-22 15:42:28 +00:00
14 changed files with 875 additions and 1457 deletions

3
.gitignore vendored
View File

@ -4,6 +4,3 @@ cli/capsule/
db.db3 db.db3
cert.pem cert.pem
key.rsa key.rsa
content/
.DS_Store
build/

View File

@ -1,11 +1,19 @@
pipeline: pipeline:
buildCli:
group: build
image: rust
commands:
- cd cli
- rustup target add x86_64-apple-darwin
- cargo build --release --target x86_64-unknown-linux-gnu
buildApi: buildApi:
group: build group: build
image: woodpeckerci/plugin-docker-buildx image: woodpeckerci/plugin-docker-buildx
secrets: [docker_username, docker_password] secrets: [docker_username, docker_password]
when: when:
path: "api/**/*" path: "api/*"
settings: settings:
repo: wilw/capsuletown-api repo: wilw/capsuletown-api
dockerfile: api/Dockerfile dockerfile: api/Dockerfile
@ -16,46 +24,22 @@ pipeline:
image: woodpeckerci/plugin-docker-buildx image: woodpeckerci/plugin-docker-buildx
secrets: [docker_username, docker_password] secrets: [docker_username, docker_password]
when: when:
path: "server/**/*" path: "server/*"
settings: settings:
repo: wilw/capsuletown-server repo: wilw/capsuletown-server
dockerfile: server/Dockerfile dockerfile: server/Dockerfile
context: server context: server
buildCli:
group: build
image: rust
when:
path: "cli/**/*"
commands:
- cd cli
- cargo build --release
- target/release/captown help
deployRootCapsule: deployRootCapsule:
group: deploy
image: python:3.10 image: python:3.10
group: build
when: when:
path: "home/**/*" path: "home/*"
secrets: [ CAPSULE_TOWN_KEY ] secrets: [ CAPSULE_TOWN_KEY ]
commands: commands:
- cd home - cd home
- CAPSULE=$(tar -czf /tmp/c.tar.gz -C capsule . && cat /tmp/c.tar.gz | base64) - CAPSULE=$(tar -czf /tmp/c.tar.gz -C capsule . && cat /tmp/c.tar.gz | base64)
- 'echo "{\"capsuleArchive\": \"$CAPSULE\"}" > /tmp/capsule_file' - 'echo "{\"capsuleArchive\": \"$CAPSULE\"}" > /tmp/capsule_file'
- 'curl -X PUT -H "Content-Type: application/json" -H "api-key: $CAPSULE_TOWN_KEY" -d @/tmp/capsule_file https://api.capsule.town/capsule' - 'curl -X PUT -H "Content-Type: application/json" -H "api-key: $CAPSULE_TOWN_KEY" -d @/tmp/capsule_file https://api.capsule.town/capsule'
deployCli:
group: deploy
image: alpine
when:
path: "cli/**/*"
secrets: [ LINODE_ACCESS_KEY, LINODE_SECRET_ACCESS_KEY, BUNNY_KEY ]
commands:
- cd cli
- apk update
- apk add s3cmd curl
- s3cmd --configure --access_key=$LINODE_ACCESS_KEY --secret_key=$LINODE_SECRET_ACCESS_KEY --host=https://eu-central-1.linodeobjects.com --host-bucket="%(bucket)s.eu-central-1.linodeobjects.com" --dump-config > /root/.s3cfg
- s3cmd -c /root/.s3cfg put target/release/captown s3://download.capsule.town/captown-linux-0.2 --acl-public
- 'curl -X POST -H "AccessKey: $BUNNY_KEY" https://api.bunny.net/pullzone/783552/purgeCache'
branches: main #branches: main

640
api/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,14 +4,15 @@ version = "0.1.0"
authors = ["Will Webberley <me@wilw.dev>"] authors = ["Will Webberley <me@wilw.dev>"]
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
rocket = "0.4.11" rocket = "0.4.8"
jsonwebtoken = "8.3.0" rocket_contrib = "0.4.6"
serde = { version = "1.0.160", features = ["derive"] } jsonwebtoken = "7.2"
flate2 = "1.0.26" serde = { version = "1.0", features = ["derive"] }
tar = "0.4.38" flate2 = "1.0.19"
base64 = "0.21.0" tar = "0.4.30"
rusqlite = "0.29.0" base64 = "0.13.0"
uuid = { version = "1.3.1", features = ["v4"] } rusqlite = "0.24.2"
ubyte = "0.10.3" uuid = { version = "0.8", features = ["v4"] }
rocket_contrib = "0.4.11"

View File

@ -3,15 +3,15 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket_contrib; #[macro_use] extern crate rocket_contrib;
use std::{env, str, fs::{self, File}, time::{SystemTime, UNIX_EPOCH}, io::Write, collections::HashSet}; use std::{env, str, fs::{self, File}, time::{SystemTime, UNIX_EPOCH}, io::Write};
use rocket::{self, routes, get, post, put, catch, config::{Config, Limits}, response::Responder, request::{self, Request, FromRequest}, Outcome, http::Status}; use rocket::{self, routes, get, post, put, config::{Config, Limits}, response::Responder, request::{self, Request, FromRequest}, Outcome, http::Status};
use rocket_contrib::json::{Json, JsonValue}; use rocket_contrib::json::{Json, JsonValue};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use jsonwebtoken::{self, encode, decode, Header, Validation, EncodingKey, DecodingKey, Algorithm}; use jsonwebtoken::{self, encode, decode, Header, Validation, EncodingKey, DecodingKey};
use rusqlite::{params, Connection}; use rusqlite::{params, Connection};
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use tar::Archive; use tar::Archive;
use base64::{Engine as _, engine::general_purpose}; use base64;
use uuid::Uuid; use uuid::Uuid;
const DB_FILE: &str = "/usr/local/var/capsules_db/db.db3"; const DB_FILE: &str = "/usr/local/var/capsules_db/db.db3";
@ -73,9 +73,10 @@ fn generate_access_token(capsule_id: &str) -> Result<String> {
// Verify the access JWT token, and checks still valid in DB. Returns the authenticated capsule. // Verify the access JWT token, and checks still valid in DB. Returns the authenticated capsule.
fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> { fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> {
// Validate the token integrity itself // Validate the token integrity itself
let mut my_validation = Validation::new(Algorithm::HS256); let my_validation = Validation {
my_validation.validate_exp = false; validate_exp: false,
my_validation.required_spec_claims = HashSet::new(); ..Default::default()
};
let claims = decode::<Claims>(&token, &DecodingKey::from_secret(get_jwt_secret().as_ref()), &my_validation)?.claims; let claims = decode::<Claims>(&token, &DecodingKey::from_secret(get_jwt_secret().as_ref()), &my_validation)?.claims;
// Verify the token in the DB and retrieve the capsule info // Verify the token in the DB and retrieve the capsule info
@ -104,11 +105,6 @@ enum Resp {
NotFound(JsonValue), NotFound(JsonValue),
} }
#[catch(400)]
fn bad_request(_: &Request) -> Resp {
return Resp::BadRequest(json!({"message": "There was a problem with your request"}));
}
#[get("/")] #[get("/")]
fn index() -> Resp { fn index() -> Resp {
return Resp::NotFound(json!({"message": "There is no resource available at this path."})); return Resp::NotFound(json!({"message": "There is no resource available at this path."}));
@ -236,7 +232,7 @@ struct CapsuleDeployRequest {
#[put("/capsule", data = "<capsule>")] #[put("/capsule", data = "<capsule>")]
fn deploy_capsule(capsule: Json<CapsuleDeployRequest>, authenticated_capsule: AuthenticatedCapsule) -> Resp { fn deploy_capsule(capsule: Json<CapsuleDeployRequest>, authenticated_capsule: AuthenticatedCapsule) -> Resp {
// Decode base64-encoded JSON capsule_archive. This gives a Vec<u8> // Decode base64-encoded JSON capsule_archive. This gives a Vec<u8>
let archive_vec: Vec<u8> = match general_purpose::STANDARD.decode(&capsule.capsule_archive) { let archive_vec: Vec<u8> = match base64::decode(&capsule.capsule_archive) {
Ok(x) => x, Ok(x) => x,
Err(_) => return Resp::BadRequest(json!({"message": "Your capsule archive is not valid"})), Err(_) => return Resp::BadRequest(json!({"message": "Your capsule archive is not valid"})),
}; };
@ -271,30 +267,6 @@ fn deploy_capsule(capsule: Json<CapsuleDeployRequest>, authenticated_capsule: Au
return Resp::Ok(json!({"message": "Your capsule was deployed", "url": url})); return Resp::Ok(json!({"message": "Your capsule was deployed", "url": url}));
} }
#[derive(Serialize)]
struct CapsuleViewLog {
path: String,
timestamp: i32,
}
#[get("/logs")]
fn get_logs(authenticated_capsule: AuthenticatedCapsule) -> Resp {
let conn = match get_db() {
Ok(c) => c,
Err(_) => return Resp::InternalServerError(json!({"message": "Database problem"})),
};
let mut stmt = conn
.prepare("SELECT path, timestamp FROM view WHERE capsule_id = ?1 ORDER BY timestamp DESC LIMIT 100")
.unwrap();
let view_results = stmt.query_map(params![authenticated_capsule.id], |row| {
Ok(CapsuleViewLog {
path: row.get(0)?,
timestamp: row.get(1)?,
})
}).unwrap();
let views: Vec<CapsuleViewLog> = view_results.map(|view| view.unwrap()).collect();
return Resp::Ok(json!({"logs": &views}));
}
fn main() { fn main() {
// Create needed directories // Create needed directories
fs::create_dir_all(CAPSULE_DIR).unwrap_or_default(); fs::create_dir_all(CAPSULE_DIR).unwrap_or_default();
@ -304,5 +276,5 @@ fn main() {
my_config.set_port(9000); my_config.set_port(9000);
my_config.set_limits(Limits::new().limit("json", 50 * 1024 * 1024)); // 50MB my_config.set_limits(Limits::new().limit("json", 50 * 1024 * 1024)); // 50MB
let app = rocket::custom(my_config); let app = rocket::custom(my_config);
app.mount("/", routes![index, create_capsule, deploy_capsule, get_logs]).launch(); app.mount("/", routes![index, create_capsule, deploy_capsule]).launch();
} }

1295
cli/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,3 @@ reqwest = { version = "0.11", features = ["json", "blocking"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_yaml = "0.8" serde_yaml = "0.8"
chrono = "0.4.24"
prettytable = "0.10.0"
openssl = { version = "0.10", features = ["vendored"] }

View File

@ -5,8 +5,6 @@ use clap::{Arg, App, SubCommand};
use flate2::{Compression, write::GzEncoder}; use flate2::{Compression, write::GzEncoder};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use tempfile::tempdir; use tempfile::tempdir;
use chrono::prelude::*;
use prettytable::{Table, row};
use dirs; use dirs;
use base64; use base64;
use reqwest; use reqwest;
@ -207,81 +205,6 @@ fn create_capsule() -> Result<bool>{
} }
} }
#[derive(Deserialize, Debug)]
struct LogsResponse {
logs: Option<Vec<Log>>,
message: Option<String>,
}
#[derive(Deserialize, Debug)]
struct Log {
path: String,
timestamp: i64,
}
impl Log {
fn time(&self) -> String {
let naive = NaiveDateTime::from_timestamp_opt(self.timestamp, 0).unwrap();
let datetime: DateTime<Utc> = DateTime::from_utc(naive, Utc);
let newdate = format!("{}", datetime.format("%Y-%m-%d %H:%M:%S"));
return newdate;
}
}
// PUTs the base64-encoded capsule tarball to the server.
fn capsule_logs(flag_capsule_name: Option<&str>, flag_number_of_logs: Option<&str>) -> Result<bool>{
let capsule_name: String = match flag_capsule_name {
Some(x) => String::from(x),
None => prompt_for("Which capsule do you want to view logs for?"),
};
let capsule_config = match read_config_capsule(&capsule_name) {
Ok(x) => x,
Err(x) => {
println!("{:?}", x);
return Err(Box::from("Unable to get logs"));
},
};
let number_of_logs: usize = match flag_number_of_logs {
Some(x) => {
let required = match x.parse::<usize>() {
Ok(y) => y,
Err(_) => return Err(Box::from("Log count must be a number")),
};
if required > 100 {
return Err(Box::from("Maximum log count is 100"));
}
required
},
None => 20,
};
let client = reqwest::blocking::Client::new();
let res = client.get(&format!("{}/logs", get_api_url()))
.header("api-key", &capsule_config.access_token).send()?;
let status = res.status();
let response_data = res.json::<LogsResponse>()?;
if status.is_success() {
match response_data.logs {
None => println!("No logs found"),
Some(mut logs) => {
logs.truncate(number_of_logs);
logs.reverse();
let mut table = Table::new();
table.add_row(row!["TIME", "CAPSULE", "PATH"]);
for log in logs {
table.add_row(row![log.time(), capsule_name, log.path]);
}
table.printstd();
},
}
return Ok(true);
} else {
let error_message = match response_data.message {
None => String::from("Unknown error"),
Some(message) => message,
};
println!("Unable to get the logs for your capsule: {}", &error_message);
return Err(Box::from("Unable to get logs"));
}
}
fn main() { fn main() {
// Setup config // Setup config
@ -291,7 +214,7 @@ fn main() {
// Read command-line commands/args // Read command-line commands/args
let app_args = App::new("Capsule.Town") let app_args = App::new("Capsule.Town")
.version("0.2") .version("0.1")
.author("Will W. (wilw.dev)") .author("Will W. (wilw.dev)")
.about("Publishes your capsule to capsule.town") .about("Publishes your capsule to capsule.town")
.subcommand(SubCommand::with_name("create") .subcommand(SubCommand::with_name("create")
@ -302,19 +225,7 @@ fn main() {
.short("c") .short("c")
.long("capsule") .long("capsule")
.takes_value(true) .takes_value(true)
.help("Name of the capsule to be published"))) .help("Name of the capsule to be published")));
.subcommand(SubCommand::with_name("logs")
.about("View access logs for your capsule")
.arg(Arg::with_name("capsule")
.short("c")
.long("capsule")
.takes_value(true)
.help("Name of the capsule to view logs for"))
.arg(Arg::with_name("number")
.short("n")
.takes_value(true)
.help("Number of logs to display (default: 20, maximum: 100)"))
);
let matches = app_args.get_matches(); let matches = app_args.get_matches();
// Handle commands // Handle commands
@ -324,17 +235,12 @@ fn main() {
let capsule_name = sub_match.value_of("capsule"); let capsule_name = sub_match.value_of("capsule");
publish_capsule(capsule_name) publish_capsule(capsule_name)
}, },
("logs", Some(sub_match)) => {
let capsule_name = sub_match.value_of("capsule");
let number_of_logs = sub_match.value_of("number");
capsule_logs(capsule_name, number_of_logs)
},
_ => { _ => {
println!("Unknown command. Available commands: create, publish, logs"); println!("Unknown command. Available commands: create, publish");
Err(Box::from("Unable to continue")) Err(Box::from("Unable to continue"))
}, },
} { } {
println!("Exiting with error: {}", err); println!("Program is exiting with error. {}", err);
std::process::exit(1); std::process::exit(1);
} }
} }

View File

@ -19,6 +19,7 @@
✨ No sign-up is required and your capsule can be live within seconds. ✨ No sign-up is required and your capsule can be live within seconds.
✨ You get a free Geminispace hosted at <yoursubdomain>.capsule.town. ✨ You get a free Geminispace hosted at <yoursubdomain>.capsule.town.
✨ You can publish entirely anonymously. ✨ You can publish entirely anonymously.
✨ There is no logging, tracking, or analytics.
🚧 This project is currently in open beta. Feedback, bug-reports, and contributions are welcome. Please see below for ways to get in touch. 🚧 This project is currently in open beta. Feedback, bug-reports, and contributions are welcome. Please see below for ways to get in touch.
@ -38,9 +39,9 @@ Think of this service as the Gemini version of static site hosting services like
## Why is it free? ## Why is it free?
capsule.town does not generate any income, and I pay for the servers and upkeep myself. capsule.town does not generate any income, and I pay for the servers/upkeep myself.
This is one way I can give back to the indie and open-source community. Your data is not sold. You can view and evaluate the source yourself (there is a link above). This is one way I can give back to the indie and open-source community. There is no logging or analytics and your data is not collected or sold. You can view and evaluate the source yourself (there is a link above).
By taking part you are certainly not the product; you are a member of the community. By taking part you are certainly not the product; you are a member of the community.

View File

@ -2,7 +2,7 @@
=> gemini://capsule.town Return home => gemini://capsule.town Return home
This page describes the rules applying to all capsules hosted on capsule.town. This page describes the Rules applying to all capsules hosted on capsule.town.
By creating and publishing your capsule, you declare that you agree to these rules. By creating and publishing your capsule, you declare that you agree to these rules.

View File

@ -25,21 +25,21 @@ You can use CURL to get the client, as described below.
For Linux: For Linux:
``` ```
➡️ curl https://download.capsule.town/captown-linux-0.2 -o captown ➡️ curl -O https://download.capsule.town/captown-linux-0.1
``` ```
For Mac: For Mac:
``` ```
➡️ curl https://download.capsule.town/captown-mac-0.2 -o captown ➡️ curl -O https://download.capsule.town/captown-mac-0.1
``` ```
We do not yet have a Windows version, but contributions are welcome. The Windows client is coming soon (contributions welcome).
Once downloaded: Once downloaded:
1. Mark the binary as executable: `chmod +x captown` 1. Mark the binary as executable: `chmod +x captown-mac-0.1`
2. Move the binary to a location of your choosing: e.g. `sudo mv captown /usr/local/bin`. 2. Move the binary to a location of your choosing: e.g. `mv captown-mac-0.1 /usr/local/bin/captown`.
The rest of this guide assumes the binary is somewhere on your `PATH` and can be invoked using `captown` (as above). The rest of this guide assumes the binary is somewhere on your `PATH` and can be invoked using `captown` (as above).
@ -103,16 +103,6 @@ Whichever route you choose, if all goes well you'll then be able to visit `gemin
🗒 Note: the `publish` command must be run from the root of your project (i.e. the directory containing the `capsule/` sub-directory). 🗒 Note: the `publish` command must be run from the root of your project (i.e. the directory containing the `capsule/` sub-directory).
### 5. View your capsule's logs
You can see an access log of your capsule by running the `logs` command:
```
➡️ captown logs -c mycapsule
```
View other options for this command by running `captown help logs`.
## Making updates ## Making updates
When you've made updates that you want to publish, simply run `captown publish` again to make them live. When you've made updates that you want to publish, simply run `captown publish` again to make them live.

117
server/Cargo.lock generated
View File

@ -1,7 +1,5 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "agate" name = "agate"
version = "2.3.0" version = "2.3.0"
@ -12,24 +10,12 @@ dependencies = [
"mime_guess", "mime_guess",
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"rusqlite",
"rustls", "rustls",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
"url", "url",
] ]
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -53,12 +39,6 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.4.0" version = "3.4.0"
@ -101,18 +81,6 @@ dependencies = [
"termcolor", "termcolor",
] ]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.0.0" version = "1.0.0"
@ -132,35 +100,6 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "getrandom"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"
dependencies = [
"hashbrown",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.17" version = "0.1.17"
@ -204,19 +143,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.142" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
[[package]]
name = "libsqlite3-sys"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "log" name = "log"
@ -299,9 +228,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.17.1" version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
@ -315,12 +244,6 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
[[package]]
name = "pkg-config"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.24" version = "1.0.24"
@ -354,20 +277,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "rusqlite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
dependencies = [
"bitflags",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"smallvec",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.19.0" version = "0.19.0"
@ -391,12 +300,6 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.3.19" version = "0.3.19"
@ -532,24 +435,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.2" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.69" version = "0.2.69"

View File

@ -21,7 +21,6 @@ once_cell = "1.4"
percent-encoding = "2.1" percent-encoding = "2.1"
rustls = "0.19.0" rustls = "0.19.0"
url = "2.1" url = "2.1"
rusqlite = "0.29.0"
[profile.release] [profile.release]
lto = true lto = true

View File

@ -14,7 +14,6 @@ use {
net::SocketAddr, net::SocketAddr,
path::Path, path::Path,
sync::Arc, sync::Arc,
time::{SystemTime, UNIX_EPOCH},
}, },
tokio::{ tokio::{
io::{AsyncReadExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncWriteExt},
@ -23,16 +22,8 @@ use {
}, },
tokio_rustls::{TlsAcceptor, server::TlsStream}, tokio_rustls::{TlsAcceptor, server::TlsStream},
url::{Host, Url}, url::{Host, Url},
rusqlite::{Connection},
}; };
const DB_FILE: &str = "/usr/local/var/capsules_db/db.db3";
// Utility function to retrieve a connection to the database
fn get_db() -> Result<Connection, rusqlite::Error> {
return Ok(Connection::open(DB_FILE)?);
}
fn main() -> Result { fn main() -> Result {
if !ARGS.silent { if !ARGS.silent {
env_logger::Builder::new().parse_filters("info").init(); env_logger::Builder::new().parse_filters("info").init();
@ -252,7 +243,7 @@ async fn send_response(url: Url, stream: &mut TlsStream<TcpStream>) -> Result {
} }
} }
} }
// Make sure the file opens successfully before sending the success header. // Make sure the file opens successfully before sending the success header.
let mut file = match tokio::fs::File::open(&path).await { let mut file = match tokio::fs::File::open(&path).await {
Ok(file) => file, Ok(file) => file,
@ -272,26 +263,6 @@ async fn send_response(url: Url, stream: &mut TlsStream<TcpStream>) -> Result {
// Send body. // Send body.
tokio::io::copy(&mut file, stream).await?; tokio::io::copy(&mut file, stream).await?;
// Capture the view
#[derive(Debug)]
struct Capsule {
id: String,
}
let conn = get_db().unwrap();
let mut stmt = conn.prepare(&format!("SELECT id, name FROM capsule WHERE name = '{}'", &subdomain))?;
let mut capsule_cursor = stmt.query_map([], |row| {
Ok(Capsule {
id: row.get(0)?,
})
})?;
let capsule = capsule_cursor.next().unwrap()?;
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
_ = conn.execute("CREATE TABLE IF NOT EXISTS view (capsule_id TEXT, path TEXT, timestamp INTEGER)", ());
conn.execute("INSERT INTO view (capsule_id, path, timestamp) VALUES (?1, ?2, ?3)",
(&capsule.id, &url.path(), timestamp),
)?;
Ok(()) Ok(())
} }