mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
2
Makefile
2
Makefile
@@ -5,7 +5,7 @@ EMBASSY_UIS := frontend/dist/ui frontend/dist/setup-wizard frontend/dist/diagnos
|
|||||||
EMBASSY_SRC := raspios.img product_key.txt $(EMBASSY_BINS) backend/embassyd.service backend/embassy-init.service $(EMBASSY_UIS) $(shell find build)
|
EMBASSY_SRC := raspios.img product_key.txt $(EMBASSY_BINS) backend/embassyd.service backend/embassy-init.service $(EMBASSY_UIS) $(shell find build)
|
||||||
COMPAT_SRC := $(shell find system-images/compat/src)
|
COMPAT_SRC := $(shell find system-images/compat/src)
|
||||||
UTILS_SRC := $(shell find system-images/utils/Dockerfile)
|
UTILS_SRC := $(shell find system-images/utils/Dockerfile)
|
||||||
BACKEND_SRC := $(shell find backend/src) $(shell find patch-db/*/src) backend/Cargo.toml backend/Cargo.lock
|
BACKEND_SRC := $(shell find backend/src) $(shell find backend/migrations) $(shell find patch-db/*/src) backend/Cargo.toml backend/Cargo.lock
|
||||||
FRONTEND_SHARED_SRC := $(shell find frontend/projects/shared) $(shell find frontend/assets) $(shell ls -p frontend/ | grep -v / | sed 's/^/frontend\//g') frontend/node_modules frontend/config.json patch-db/client/dist
|
FRONTEND_SHARED_SRC := $(shell find frontend/projects/shared) $(shell find frontend/assets) $(shell ls -p frontend/ | grep -v / | sed 's/^/frontend\//g') frontend/node_modules frontend/config.json patch-db/client/dist
|
||||||
FRONTEND_UI_SRC := $(shell find frontend/projects/ui)
|
FRONTEND_UI_SRC := $(shell find frontend/projects/ui)
|
||||||
FRONTEND_SETUP_WIZARD_SRC := $(shell find frontend/projects/setup-wizard)
|
FRONTEND_SETUP_WIZARD_SRC := $(shell find frontend/projects/setup-wizard)
|
||||||
|
|||||||
98
backend/Cargo.lock
generated
98
backend/Cargo.lock
generated
@@ -982,6 +982,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-next"
|
name = "dirs-next"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -992,6 +1001,17 @@ dependencies = [
|
|||||||
"dirs-sys-next",
|
"dirs-sys-next",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"redox_users 0.4.3",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-sys-next"
|
name = "dirs-sys-next"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -1302,18 +1322,6 @@ version = "0.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flume"
|
|
||||||
version = "0.10.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
"pin-project",
|
|
||||||
"spin 0.9.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -1641,6 +1649,15 @@ version = "0.4.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hkdf"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
|
||||||
|
dependencies = [
|
||||||
|
"hmac 0.12.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hmac"
|
name = "hmac"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@@ -2151,17 +2168,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libsqlite3-sys"
|
|
||||||
version = "0.24.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
@@ -2213,6 +2219,15 @@ dependencies = [
|
|||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md-5"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582"
|
||||||
|
dependencies = [
|
||||||
|
"digest 0.10.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -2509,7 +2524,7 @@ checksum = "e7249a699cdeea261ac73f1bf9350777cb867324f44373aafb5a287365bf1771"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.13.0",
|
"base64 0.13.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"md-5",
|
"md-5 0.9.1",
|
||||||
"sha2 0.9.9",
|
"sha2 0.9.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@@ -3219,7 +3234,7 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"spin 0.5.2",
|
"spin",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -3725,15 +3740,6 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
|
||||||
dependencies = [
|
|
||||||
"lock_api",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spki"
|
name = "spki"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@@ -3773,34 +3779,39 @@ checksum = "6b69bf218860335ddda60d6ce85ee39f6cf6e5630e300e19757d1de15886a093"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"atoi",
|
"atoi",
|
||||||
|
"base64 0.13.0",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
|
"dirs 4.0.0",
|
||||||
"either",
|
"either",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"flume",
|
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-executor",
|
|
||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"hex",
|
"hex",
|
||||||
|
"hkdf",
|
||||||
|
"hmac 0.12.1",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itoa 1.0.2",
|
"itoa 1.0.2",
|
||||||
"libc",
|
"libc",
|
||||||
"libsqlite3-sys",
|
|
||||||
"log",
|
"log",
|
||||||
|
"md-5 0.10.1",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"rand 0.8.5",
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sha-1",
|
||||||
"sha2 0.10.2",
|
"sha2 0.10.2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"sqlformat",
|
"sqlformat",
|
||||||
@@ -3810,6 +3821,7 @@ dependencies = [
|
|||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"url",
|
"url",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4356,7 +4368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
|
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"dirs",
|
"dirs 1.0.5",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5167,6 +5179,16 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "whoami"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ sqlx = { version = "0.6.0", features = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"offline",
|
"offline",
|
||||||
"runtime-tokio-rustls",
|
"runtime-tokio-rustls",
|
||||||
"sqlite",
|
"postgres",
|
||||||
] }
|
] }
|
||||||
stderrlog = "0.5.3"
|
stderrlog = "0.5.3"
|
||||||
tar = "0.4.38"
|
tar = "0.4.38"
|
||||||
@@ -142,8 +142,11 @@ trust-dns-server = "0.21.2"
|
|||||||
typed-builder = "0.10.0"
|
typed-builder = "0.10.0"
|
||||||
url = { version = "2.2.2", features = ["serde"] }
|
url = { version = "2.2.2", features = ["serde"] }
|
||||||
|
|
||||||
|
[profile.test]
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
[profile.dev.package.backtrace]
|
[profile.dev.package.backtrace]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[profile.test]
|
[profile.dev.package.sqlx-macros]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
@@ -1,45 +1,47 @@
|
|||||||
-- Add migration script here
|
-- Add migration script here
|
||||||
CREATE TABLE IF NOT EXISTS tor
|
CREATE TABLE IF NOT EXISTS tor (
|
||||||
(
|
package TEXT NOT NULL,
|
||||||
package TEXT NOT NULL,
|
interface TEXT NOT NULL,
|
||||||
interface TEXT NOT NULL,
|
key BYTEA NOT NULL CHECK (length(key) = 64),
|
||||||
key BLOB NOT NULL CHECK (length(key) = 64),
|
|
||||||
PRIMARY KEY (package, interface)
|
PRIMARY KEY (package, interface)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS session
|
|
||||||
(
|
CREATE TABLE IF NOT EXISTS session (
|
||||||
id TEXT NOT NULL PRIMARY KEY,
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
logged_in TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
logged_in TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
logged_out TIMESTAMP,
|
logged_out TIMESTAMP,
|
||||||
last_active TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
last_active TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
user_agent TEXT,
|
user_agent TEXT,
|
||||||
metadata TEXT NOT NULL DEFAULT 'null'
|
metadata TEXT NOT NULL DEFAULT 'null'
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS account
|
|
||||||
(
|
CREATE TABLE IF NOT EXISTS account (
|
||||||
id INTEGER PRIMARY KEY CHECK (id = 0),
|
id SERIAL PRIMARY KEY CHECK (id = 0),
|
||||||
password TEXT NOT NULL,
|
password TEXT NOT NULL,
|
||||||
tor_key BLOB NOT NULL CHECK (length(tor_key) = 64)
|
tor_key BYTEA NOT NULL CHECK (length(tor_key) = 64)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS ssh_keys
|
|
||||||
(
|
CREATE TABLE IF NOT EXISTS ssh_keys (
|
||||||
fingerprint TEXT NOT NULL,
|
fingerprint TEXT NOT NULL,
|
||||||
openssh_pubkey TEXT NOT NULL,
|
openssh_pubkey TEXT NOT NULL,
|
||||||
created_at TEXT NOT NULL,
|
created_at TEXT NOT NULL,
|
||||||
PRIMARY KEY (fingerprint)
|
PRIMARY KEY (fingerprint)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS certificates
|
|
||||||
(
|
CREATE TABLE IF NOT EXISTS certificates (
|
||||||
id INTEGER PRIMARY KEY, -- Root = 0, Int = 1, Other = 2..
|
id SERIAL PRIMARY KEY,
|
||||||
|
-- Root = 0, Int = 1, Other = 2..
|
||||||
priv_key_pem TEXT NOT NULL,
|
priv_key_pem TEXT NOT NULL,
|
||||||
certificate_pem TEXT NOT NULL,
|
certificate_pem TEXT NOT NULL,
|
||||||
lookup_string TEXT UNIQUE,
|
lookup_string TEXT UNIQUE,
|
||||||
created_at TEXT,
|
created_at TEXT,
|
||||||
updated_at TEXT
|
updated_at TEXT
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS notifications
|
|
||||||
(
|
ALTER SEQUENCE certificates_id_seq START 2 RESTART 2;
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
|
CREATE TABLE IF NOT EXISTS notifications (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
package_id TEXT,
|
package_id TEXT,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
code INTEGER NOT NULL,
|
code INTEGER NOT NULL,
|
||||||
@@ -48,9 +50,9 @@ CREATE TABLE IF NOT EXISTS notifications
|
|||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
data TEXT
|
data TEXT
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS cifs_shares
|
|
||||||
(
|
CREATE TABLE IF NOT EXISTS cifs_shares (
|
||||||
id INTEGER PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
hostname TEXT NOT NULL,
|
hostname TEXT NOT NULL,
|
||||||
path TEXT NOT NULL,
|
path TEXT NOT NULL,
|
||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ use rpc_toolkit::command_helpers::prelude::{RequestParts, ResponseParts};
|
|||||||
use rpc_toolkit::yajrc::RpcError;
|
use rpc_toolkit::yajrc::RpcError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::context::{CliContext, RpcContext};
|
use crate::context::{CliContext, RpcContext};
|
||||||
@@ -87,7 +87,7 @@ pub fn check_password(hash: &str, password: &str) -> Result<(), Error> {
|
|||||||
|
|
||||||
pub async fn check_password_against_db<Ex>(secrets: &mut Ex, password: &str) -> Result<(), Error>
|
pub async fn check_password_against_db<Ex>(secrets: &mut Ex, password: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let pw_hash = sqlx::query!("SELECT password FROM account")
|
let pw_hash = sqlx::query!("SELECT password FROM account")
|
||||||
.fetch_one(secrets)
|
.fetch_one(secrets)
|
||||||
@@ -124,7 +124,7 @@ pub async fn login(
|
|||||||
let metadata = serde_json::to_string(&metadata).with_kind(crate::ErrorKind::Database)?;
|
let metadata = serde_json::to_string(&metadata).with_kind(crate::ErrorKind::Database)?;
|
||||||
let hash_token_hashed = hash_token.hashed();
|
let hash_token_hashed = hash_token.hashed();
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO session (id, user_agent, metadata) VALUES (?, ?, ?)",
|
"INSERT INTO session (id, user_agent, metadata) VALUES ($1, $2, $3)",
|
||||||
hash_token_hashed,
|
hash_token_hashed,
|
||||||
user_agent,
|
user_agent,
|
||||||
metadata,
|
metadata,
|
||||||
@@ -328,7 +328,7 @@ pub async fn set_password<Db: DbHandle, Ex>(
|
|||||||
password: &str,
|
password: &str,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let password = argon2::hash_encoded(
|
let password = argon2::hash_encoded(
|
||||||
password.as_bytes(),
|
password.as_bytes(),
|
||||||
@@ -337,7 +337,7 @@ where
|
|||||||
)
|
)
|
||||||
.with_kind(crate::ErrorKind::PasswordHashGeneration)?;
|
.with_kind(crate::ErrorKind::PasswordHashGeneration)?;
|
||||||
|
|
||||||
sqlx::query!("UPDATE account SET password = ?", password,)
|
sqlx::query!("UPDATE account SET password = $1", password,)
|
||||||
.execute(secrets)
|
.execute(secrets)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use patch_db::{DbHandle, HasModel, LockType};
|
|||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
@@ -195,7 +195,7 @@ impl BackupActions {
|
|||||||
volumes: &Volumes,
|
volumes: &Volumes,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let mut volumes = volumes.clone();
|
let mut volumes = volumes.clone();
|
||||||
volumes.insert(VolumeId::Backup, Volume::Backup { readonly: true });
|
volumes.insert(VolumeId::Backup, Volume::Backup { readonly: true });
|
||||||
@@ -231,7 +231,7 @@ impl BackupActions {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"REPLACE INTO tor (package, interface, key) VALUES (?, ?, ?)",
|
"INSERT INTO tor (package, interface, key) VALUES ($1, $2, $3) ON CONFLICT (package, interface) DO UPDATE SET key = $3",
|
||||||
**pkg_id,
|
**pkg_id,
|
||||||
*iface,
|
*iface,
|
||||||
key_vec,
|
key_vec,
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ pub async fn recover_full_embassy(
|
|||||||
let key_vec = os_backup.tor_key.as_bytes().to_vec();
|
let key_vec = os_backup.tor_key.as_bytes().to_vec();
|
||||||
let secret_store = ctx.secret_store().await?;
|
let secret_store = ctx.secret_store().await?;
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"REPLACE INTO account (id, password, tor_key) VALUES (?, ?, ?)",
|
"INSERT INTO account (id, password, tor_key) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET password = $2, tor_key = $3",
|
||||||
0,
|
0,
|
||||||
password,
|
password,
|
||||||
key_vec,
|
key_vec,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use color_eyre::eyre::eyre;
|
|||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
|
|
||||||
use super::{BackupTarget, BackupTargetId};
|
use super::{BackupTarget, BackupTargetId};
|
||||||
use crate::context::RpcContext;
|
use crate::context::RpcContext;
|
||||||
@@ -49,8 +49,8 @@ pub async fn add(
|
|||||||
let embassy_os = recovery_info(&guard).await?;
|
let embassy_os = recovery_info(&guard).await?;
|
||||||
guard.unmount().await?;
|
guard.unmount().await?;
|
||||||
let path_string = Path::new("/").join(&cifs.path).display().to_string();
|
let path_string = Path::new("/").join(&cifs.path).display().to_string();
|
||||||
let id: u32 = sqlx::query!(
|
let id: i32 = sqlx::query!(
|
||||||
"INSERT INTO cifs_shares (hostname, path, username, password) VALUES (?, ?, ?, ?) RETURNING id AS \"id: u32\"",
|
"INSERT INTO cifs_shares (hostname, path, username, password) VALUES ($1, $2, $3, $4) RETURNING id",
|
||||||
cifs.hostname,
|
cifs.hostname,
|
||||||
path_string,
|
path_string,
|
||||||
cifs.username,
|
cifs.username,
|
||||||
@@ -98,7 +98,7 @@ pub async fn update(
|
|||||||
guard.unmount().await?;
|
guard.unmount().await?;
|
||||||
let path_string = Path::new("/").join(&cifs.path).display().to_string();
|
let path_string = Path::new("/").join(&cifs.path).display().to_string();
|
||||||
if sqlx::query!(
|
if sqlx::query!(
|
||||||
"UPDATE cifs_shares SET hostname = ?, path = ?, username = ?, password = ? WHERE id = ?",
|
"UPDATE cifs_shares SET hostname = $1, path = $2, username = $3, password = $4 WHERE id = $5",
|
||||||
cifs.hostname,
|
cifs.hostname,
|
||||||
path_string,
|
path_string,
|
||||||
cifs.username,
|
cifs.username,
|
||||||
@@ -137,7 +137,7 @@ pub async fn remove(#[context] ctx: RpcContext, #[arg] id: BackupTargetId) -> Re
|
|||||||
crate::ErrorKind::NotFound,
|
crate::ErrorKind::NotFound,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
if sqlx::query!("DELETE FROM cifs_shares WHERE id = ?", id)
|
if sqlx::query!("DELETE FROM cifs_shares WHERE id = $1", id)
|
||||||
.execute(&ctx.secret_store)
|
.execute(&ctx.secret_store)
|
||||||
.await?
|
.await?
|
||||||
.rows_affected()
|
.rows_affected()
|
||||||
@@ -151,12 +151,12 @@ pub async fn remove(#[context] ctx: RpcContext, #[arg] id: BackupTargetId) -> Re
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load<Ex>(secrets: &mut Ex, id: u32) -> Result<Cifs, Error>
|
pub async fn load<Ex>(secrets: &mut Ex, id: i32) -> Result<Cifs, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let record = sqlx::query!(
|
let record = sqlx::query!(
|
||||||
"SELECT hostname, path, username, password FROM cifs_shares WHERE id = ?",
|
"SELECT hostname, path, username, password FROM cifs_shares WHERE id = $1",
|
||||||
id
|
id
|
||||||
)
|
)
|
||||||
.fetch_one(secrets)
|
.fetch_one(secrets)
|
||||||
@@ -170,14 +170,13 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list<Ex>(secrets: &mut Ex) -> Result<Vec<(u32, CifsBackupTarget)>, Error>
|
pub async fn list<Ex>(secrets: &mut Ex) -> Result<Vec<(i32, CifsBackupTarget)>, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let mut records = sqlx::query!(
|
let mut records =
|
||||||
"SELECT id AS \"id: u32\", hostname, path, username, password FROM cifs_shares"
|
sqlx::query!("SELECT id, hostname, path, username, password FROM cifs_shares")
|
||||||
)
|
.fetch_many(secrets);
|
||||||
.fetch_many(secrets);
|
|
||||||
|
|
||||||
let mut cifs = Vec::new();
|
let mut cifs = Vec::new();
|
||||||
while let Some(query_result) = records.try_next().await? {
|
while let Some(query_result) = records.try_next().await? {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use digest::OutputSizeUser;
|
|||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use self::cifs::CifsBackupTarget;
|
use self::cifs::CifsBackupTarget;
|
||||||
@@ -45,12 +45,12 @@ pub enum BackupTarget {
|
|||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum BackupTargetId {
|
pub enum BackupTargetId {
|
||||||
Disk { logicalname: PathBuf },
|
Disk { logicalname: PathBuf },
|
||||||
Cifs { id: u32 },
|
Cifs { id: i32 },
|
||||||
}
|
}
|
||||||
impl BackupTargetId {
|
impl BackupTargetId {
|
||||||
pub async fn load<Ex>(self, secrets: &mut Ex) -> Result<BackupTargetFS, Error>
|
pub async fn load<Ex>(self, secrets: &mut Ex) -> Result<BackupTargetFS, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
BackupTargetId::Disk { logicalname } => {
|
BackupTargetId::Disk { logicalname } => {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use regex::Regex;
|
|||||||
use serde::de::{MapAccess, Visitor};
|
use serde::de::{MapAccess, Visitor};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_json::{Number, Value};
|
use serde_json::{Number, Value};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use super::util::{self, CharSet, NumRange, UniqueBy, STATIC_NULL};
|
use super::util::{self, CharSet, NumRange, UniqueBy, STATIC_NULL};
|
||||||
use super::{Config, MatchError, NoMatchWithPath, TimeoutError, TypeOf};
|
use super::{Config, MatchError, NoMatchWithPath, TimeoutError, TypeOf};
|
||||||
@@ -2050,7 +2050,7 @@ impl TorKeyPointer {
|
|||||||
async fn deref(
|
async fn deref(
|
||||||
&self,
|
&self,
|
||||||
source_package: &PackageId,
|
source_package: &PackageId,
|
||||||
secrets: &SqlitePool,
|
secrets: &PgPool,
|
||||||
) -> Result<Value, ConfigurationError> {
|
) -> Result<Value, ConfigurationError> {
|
||||||
if &self.package_id != source_package {
|
if &self.package_id != source_package {
|
||||||
return Err(ConfigurationError::PermissionDenied(
|
return Err(ConfigurationError::PermissionDenied(
|
||||||
@@ -2058,7 +2058,7 @@ impl TorKeyPointer {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let x = sqlx::query!(
|
let x = sqlx::query!(
|
||||||
"SELECT key FROM tor WHERE package = ? AND interface = ?",
|
"SELECT key FROM tor WHERE package = $1 AND interface = $2",
|
||||||
*self.package_id,
|
*self.package_id,
|
||||||
*self.interface
|
*self.interface
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use std::ops::Deref;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use helpers::to_tmp_path;
|
use helpers::to_tmp_path;
|
||||||
@@ -14,8 +13,8 @@ use reqwest::Url;
|
|||||||
use rpc_toolkit::url::Host;
|
use rpc_toolkit::url::Host;
|
||||||
use rpc_toolkit::Context;
|
use rpc_toolkit::Context;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::sqlite::SqliteConnectOptions;
|
use sqlx::postgres::PgConnectOptions;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::PgPool;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::sync::{broadcast, oneshot, Mutex, RwLock};
|
use tokio::sync::{broadcast, oneshot, Mutex, RwLock};
|
||||||
@@ -24,6 +23,7 @@ use tracing::instrument;
|
|||||||
use crate::core::rpc_continuations::{RequestGuid, RestHandler, RpcContinuation};
|
use crate::core::rpc_continuations::{RequestGuid, RestHandler, RpcContinuation};
|
||||||
use crate::db::model::{Database, InstalledPackageDataEntry, PackageDataEntry};
|
use crate::db::model::{Database, InstalledPackageDataEntry, PackageDataEntry};
|
||||||
use crate::hostname::{derive_hostname, derive_id, get_product_key};
|
use crate::hostname::{derive_hostname, derive_id, get_product_key};
|
||||||
|
use crate::init::{init_postgres, pgloader};
|
||||||
use crate::install::cleanup::{cleanup_failed, uninstall, CleanupFailedReceipts};
|
use crate::install::cleanup::{cleanup_failed, uninstall, CleanupFailedReceipts};
|
||||||
use crate::manager::ManagerMap;
|
use crate::manager::ManagerMap;
|
||||||
use crate::middleware::auth::HashSessionToken;
|
use crate::middleware::auth::HashSessionToken;
|
||||||
@@ -71,7 +71,7 @@ impl RpcContextConfig {
|
|||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or_else(|| Path::new("/embassy-data"))
|
.unwrap_or_else(|| Path::new("/embassy-data"))
|
||||||
}
|
}
|
||||||
pub async fn db(&self, secret_store: &SqlitePool, product_key: &str) -> Result<PatchDb, Error> {
|
pub async fn db(&self, secret_store: &PgPool, product_key: &str) -> Result<PatchDb, Error> {
|
||||||
let sid = derive_id(product_key);
|
let sid = derive_id(product_key);
|
||||||
let hostname = derive_hostname(&sid);
|
let hostname = derive_hostname(&sid);
|
||||||
let db_path = self.datadir().join("main").join("embassy.db");
|
let db_path = self.datadir().join("main").join("embassy.db");
|
||||||
@@ -94,18 +94,19 @@ impl RpcContextConfig {
|
|||||||
Ok(db)
|
Ok(db)
|
||||||
}
|
}
|
||||||
#[instrument]
|
#[instrument]
|
||||||
pub async fn secret_store(&self) -> Result<SqlitePool, Error> {
|
pub async fn secret_store(&self) -> Result<PgPool, Error> {
|
||||||
let secret_store = SqlitePool::connect_with(
|
init_postgres(self.datadir()).await?;
|
||||||
SqliteConnectOptions::new()
|
let secret_store =
|
||||||
.filename(self.datadir().join("main").join("secrets.db"))
|
PgPool::connect_with(PgConnectOptions::new().database("secrets").username("root"))
|
||||||
.create_if_missing(true)
|
.await?;
|
||||||
.busy_timeout(Duration::from_secs(30)),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
sqlx::migrate!()
|
sqlx::migrate!()
|
||||||
.run(&secret_store)
|
.run(&secret_store)
|
||||||
.await
|
.await
|
||||||
.with_kind(crate::ErrorKind::Database)?;
|
.with_kind(crate::ErrorKind::Database)?;
|
||||||
|
let old_db_path = self.datadir().join("main/secrets.db");
|
||||||
|
if tokio::fs::metadata(&old_db_path).await.is_ok() {
|
||||||
|
pgloader(&old_db_path).await?;
|
||||||
|
}
|
||||||
Ok(secret_store)
|
Ok(secret_store)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +119,7 @@ pub struct RpcContextSeed {
|
|||||||
pub datadir: PathBuf,
|
pub datadir: PathBuf,
|
||||||
pub disk_guid: Arc<String>,
|
pub disk_guid: Arc<String>,
|
||||||
pub db: PatchDb,
|
pub db: PatchDb,
|
||||||
pub secret_store: SqlitePool,
|
pub secret_store: PgPool,
|
||||||
pub docker: Docker,
|
pub docker: Docker,
|
||||||
pub net_controller: NetController,
|
pub net_controller: NetController,
|
||||||
pub managers: ManagerMap,
|
pub managers: ManagerMap,
|
||||||
@@ -214,7 +215,7 @@ impl RpcContext {
|
|||||||
)));
|
)));
|
||||||
let (shutdown, _) = tokio::sync::broadcast::channel(1);
|
let (shutdown, _) = tokio::sync::broadcast::channel(1);
|
||||||
let secret_store = base.secret_store().await?;
|
let secret_store = base.secret_store().await?;
|
||||||
tracing::info!("Opened Sqlite DB");
|
tracing::info!("Opened Pg DB");
|
||||||
let db = base.db(&secret_store, &get_product_key().await?).await?;
|
let db = base.db(&secret_store, &get_product_key().await?).await?;
|
||||||
tracing::info!("Opened PatchDB");
|
tracing::info!("Opened PatchDB");
|
||||||
let docker = Docker::connect_with_unix_defaults()?;
|
let docker = Docker::connect_with_unix_defaults()?;
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ use patch_db::PatchDb;
|
|||||||
use rpc_toolkit::yajrc::RpcError;
|
use rpc_toolkit::yajrc::RpcError;
|
||||||
use rpc_toolkit::Context;
|
use rpc_toolkit::Context;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::sqlite::SqliteConnectOptions;
|
use sqlx::postgres::PgConnectOptions;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::PgPool;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
|
use tokio::process::Command;
|
||||||
use tokio::sync::broadcast::Sender;
|
use tokio::sync::broadcast::Sender;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
@@ -19,10 +20,11 @@ use url::Host;
|
|||||||
|
|
||||||
use crate::db::model::Database;
|
use crate::db::model::Database;
|
||||||
use crate::hostname::{derive_hostname, derive_id, get_product_key};
|
use crate::hostname::{derive_hostname, derive_id, get_product_key};
|
||||||
|
use crate::init::{init_postgres, pgloader};
|
||||||
use crate::net::tor::os_key;
|
use crate::net::tor::os_key;
|
||||||
use crate::setup::{password_hash, RecoveryStatus};
|
use crate::setup::{password_hash, RecoveryStatus};
|
||||||
use crate::util::io::from_yaml_async_reader;
|
use crate::util::io::from_yaml_async_reader;
|
||||||
use crate::util::AsyncFileExt;
|
use crate::util::{AsyncFileExt, Invoke};
|
||||||
use crate::{Error, ResultExt};
|
use crate::{Error, ResultExt};
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
@@ -93,7 +95,7 @@ impl SetupContext {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
pub async fn db(&self, secret_store: &SqlitePool) -> Result<PatchDb, Error> {
|
pub async fn db(&self, secret_store: &PgPool) -> Result<PatchDb, Error> {
|
||||||
let db_path = self.datadir.join("main").join("embassy.db");
|
let db_path = self.datadir.join("main").join("embassy.db");
|
||||||
let db = PatchDb::open(&db_path)
|
let db = PatchDb::open(&db_path)
|
||||||
.await
|
.await
|
||||||
@@ -117,18 +119,19 @@ impl SetupContext {
|
|||||||
Ok(db)
|
Ok(db)
|
||||||
}
|
}
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
pub async fn secret_store(&self) -> Result<SqlitePool, Error> {
|
pub async fn secret_store(&self) -> Result<PgPool, Error> {
|
||||||
let secret_store = SqlitePool::connect_with(
|
init_postgres(&self.datadir).await?;
|
||||||
SqliteConnectOptions::new()
|
let secret_store =
|
||||||
.filename(self.datadir.join("main").join("secrets.db"))
|
PgPool::connect_with(PgConnectOptions::new().database("secrets").username("root"))
|
||||||
.create_if_missing(true)
|
.await?;
|
||||||
.busy_timeout(Duration::from_secs(30)),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
sqlx::migrate!()
|
sqlx::migrate!()
|
||||||
.run(&secret_store)
|
.run(&secret_store)
|
||||||
.await
|
.await
|
||||||
.with_kind(crate::ErrorKind::Database)?;
|
.with_kind(crate::ErrorKind::Database)?;
|
||||||
|
let old_db_path = self.datadir.join("main/secrets.db");
|
||||||
|
if tokio::fs::metadata(&old_db_path).await.is_ok() {
|
||||||
|
pgloader(&old_db_path).await?;
|
||||||
|
}
|
||||||
Ok(secret_store)
|
Ok(secret_store)
|
||||||
}
|
}
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
|
|||||||
@@ -48,13 +48,15 @@ pub async fn unmount<P: AsRef<Path>>(mountpoint: P) -> Result<(), Error> {
|
|||||||
.arg(mountpoint.as_ref())
|
.arg(mountpoint.as_ref())
|
||||||
.invoke(crate::ErrorKind::Filesystem)
|
.invoke(crate::ErrorKind::Filesystem)
|
||||||
.await?;
|
.await?;
|
||||||
tokio::fs::remove_dir_all(mountpoint.as_ref())
|
match tokio::fs::remove_dir(mountpoint.as_ref()).await {
|
||||||
.await
|
Err(e) if e.raw_os_error() == Some(39) => Ok(()), // directory not empty
|
||||||
.with_ctx(|_| {
|
a => a,
|
||||||
(
|
}
|
||||||
crate::ErrorKind::Filesystem,
|
.with_ctx(|_| {
|
||||||
format!("rm {}", mountpoint.as_ref().display()),
|
(
|
||||||
)
|
crate::ErrorKind::Filesystem,
|
||||||
})?;
|
format!("rm {}", mountpoint.as_ref().display()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
use std::process::Stdio;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
use patch_db::{DbHandle, LockReceipt, LockType};
|
use patch_db::{DbHandle, LockReceipt, LockType};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
use crate::context::rpc::RpcContextConfig;
|
use crate::context::rpc::RpcContextConfig;
|
||||||
use crate::db::model::ServerStatus;
|
use crate::db::model::ServerStatus;
|
||||||
|
use crate::disk::mount::util::unmount;
|
||||||
use crate::install::PKG_DOCKER_DIR;
|
use crate::install::PKG_DOCKER_DIR;
|
||||||
use crate::util::Invoke;
|
use crate::util::Invoke;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
@@ -67,10 +71,91 @@ impl InitReceipts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn pgloader(old_db_path: impl AsRef<Path>) -> Result<(), Error> {
|
||||||
|
tokio::fs::write(
|
||||||
|
"/etc/embassy/migrate.load",
|
||||||
|
format!(
|
||||||
|
include_str!("migrate.load"),
|
||||||
|
sqlite_path = old_db_path.as_ref().display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
tracing::info!("Running pgloader");
|
||||||
|
let out = Command::new("pgloader")
|
||||||
|
.arg("-v")
|
||||||
|
.arg("/etc/embassy/migrate.load")
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
let stdout = String::from_utf8(out.stdout)?;
|
||||||
|
for line in stdout.lines() {
|
||||||
|
tracing::debug!("pgloader: {}", line);
|
||||||
|
}
|
||||||
|
let stderr = String::from_utf8(out.stderr)?;
|
||||||
|
for line in stderr.lines() {
|
||||||
|
tracing::debug!("pgloader err: {}", line);
|
||||||
|
}
|
||||||
|
tracing::debug!("pgloader exited with code {:?}", out.status);
|
||||||
|
if let Some(err) = stdout.lines().chain(stderr.lines()).find_map(|l| {
|
||||||
|
if l.split_ascii_whitespace()
|
||||||
|
.any(|word| word == "ERROR" || word == "FATAL")
|
||||||
|
{
|
||||||
|
Some(l)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return Err(Error::new(
|
||||||
|
eyre!("pgloader error: {}", err),
|
||||||
|
crate::ErrorKind::Database,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
tokio::fs::rename(
|
||||||
|
old_db_path.as_ref(),
|
||||||
|
old_db_path.as_ref().with_extension("bak"),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be idempotent
|
||||||
|
pub async fn init_postgres(datadir: impl AsRef<Path>) -> Result<(), Error> {
|
||||||
|
let db_dir = datadir.as_ref().join("main/postgresql");
|
||||||
|
let is_mountpoint = || async {
|
||||||
|
Ok::<_, Error>(
|
||||||
|
tokio::process::Command::new("mountpoint")
|
||||||
|
.arg("/var/lib/postgresql")
|
||||||
|
.stdout(std::process::Stdio::null())
|
||||||
|
.stderr(std::process::Stdio::null())
|
||||||
|
.status()
|
||||||
|
.await?
|
||||||
|
.success(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if tokio::fs::metadata(&db_dir).await.is_err() {
|
||||||
|
Command::new("cp")
|
||||||
|
.arg("-ra")
|
||||||
|
.arg("/var/lib/postgresql")
|
||||||
|
.arg(&db_dir)
|
||||||
|
.invoke(crate::ErrorKind::Filesystem)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
if !is_mountpoint().await? {
|
||||||
|
crate::disk::mount::util::bind(&db_dir, "/var/lib/postgresql", false).await?;
|
||||||
|
}
|
||||||
|
Command::new("systemctl")
|
||||||
|
.arg("start")
|
||||||
|
.arg("postgresql")
|
||||||
|
.invoke(crate::ErrorKind::Database)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn init(cfg: &RpcContextConfig, product_key: &str) -> Result<(), Error> {
|
pub async fn init(cfg: &RpcContextConfig, product_key: &str) -> Result<(), Error> {
|
||||||
let should_rebuild = tokio::fs::metadata(SYSTEM_REBUILD_PATH).await.is_ok();
|
let should_rebuild = tokio::fs::metadata(SYSTEM_REBUILD_PATH).await.is_ok();
|
||||||
let secret_store = cfg.secret_store().await?;
|
let secret_store = cfg.secret_store().await?;
|
||||||
let log_dir = cfg.datadir().join("main").join("logs");
|
let log_dir = cfg.datadir().join("main/logs");
|
||||||
if tokio::fs::metadata(&log_dir).await.is_err() {
|
if tokio::fs::metadata(&log_dir).await.is_err() {
|
||||||
tokio::fs::create_dir_all(&log_dir).await?;
|
tokio::fs::create_dir_all(&log_dir).await?;
|
||||||
}
|
}
|
||||||
@@ -92,7 +177,7 @@ pub async fn init(cfg: &RpcContextConfig, product_key: &str) -> Result<(), Error
|
|||||||
tokio::fs::remove_dir_all(&tmp_docker).await?;
|
tokio::fs::remove_dir_all(&tmp_docker).await?;
|
||||||
}
|
}
|
||||||
Command::new("cp")
|
Command::new("cp")
|
||||||
.arg("-r")
|
.arg("-ra")
|
||||||
.arg("/var/lib/docker")
|
.arg("/var/lib/docker")
|
||||||
.arg(&tmp_docker)
|
.arg(&tmp_docker)
|
||||||
.invoke(crate::ErrorKind::Filesystem)
|
.invoke(crate::ErrorKind::Filesystem)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use bollard::image::ListImagesOptions;
|
use bollard::image::ListImagesOptions;
|
||||||
use patch_db::{DbHandle, LockReceipt, LockTargetId, LockType, PatchDbHandle, Verifier};
|
use patch_db::{DbHandle, LockReceipt, LockTargetId, LockType, PatchDbHandle, Verifier};
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::{PKG_ARCHIVE_DIR, PKG_DOCKER_DIR};
|
use super::{PKG_ARCHIVE_DIR, PKG_DOCKER_DIR};
|
||||||
@@ -337,7 +337,7 @@ pub async fn uninstall<Ex>(
|
|||||||
id: &PackageId,
|
id: &PackageId,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let mut tx = db.begin().await?;
|
let mut tx = db.begin().await?;
|
||||||
let receipts = UninstallReceipts::new(&mut tx, id).await?;
|
let receipts = UninstallReceipts::new(&mut tx, id).await?;
|
||||||
@@ -383,10 +383,10 @@ where
|
|||||||
#[instrument(skip(secrets))]
|
#[instrument(skip(secrets))]
|
||||||
pub async fn remove_tor_keys<Ex>(secrets: &mut Ex, id: &PackageId) -> Result<(), Error>
|
pub async fn remove_tor_keys<Ex>(secrets: &mut Ex, id: &PackageId) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let id_str = id.as_str();
|
let id_str = id.as_str();
|
||||||
sqlx::query!("DELETE FROM tor WHERE package = ?", id_str)
|
sqlx::query!("DELETE FROM tor WHERE package = $1", id_str)
|
||||||
.execute(secrets)
|
.execute(secrets)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub const DEFAULT_MARKETPLACE: &str = "https://marketplace.start9.com";
|
pub const DEFAULT_MARKETPLACE: &str = "https://registry.start9.com";
|
||||||
pub const BUFFER_SIZE: usize = 1024;
|
pub const BUFFER_SIZE: usize = 1024;
|
||||||
pub const HOST_IP: [u8; 4] = [172, 18, 0, 1];
|
pub const HOST_IP: [u8; 4] = [172, 18, 0, 1];
|
||||||
pub const TARGET: &str = current_platform::CURRENT_PLATFORM;
|
pub const TARGET: &str = current_platform::CURRENT_PLATFORM;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use color_eyre::eyre::eyre;
|
|||||||
use nix::sys::signal::Signal;
|
use nix::sys::signal::Signal;
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
use patch_db::DbHandle;
|
use patch_db::DbHandle;
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use tokio::sync::watch::error::RecvError;
|
use tokio::sync::watch::error::RecvError;
|
||||||
use tokio::sync::watch::{channel, Receiver, Sender};
|
use tokio::sync::watch::{channel, Receiver, Sender};
|
||||||
use tokio::sync::{Notify, RwLock};
|
use tokio::sync::{Notify, RwLock};
|
||||||
@@ -47,7 +47,7 @@ impl ManagerMap {
|
|||||||
secrets: &mut Ex,
|
secrets: &mut Ex,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let mut res = BTreeMap::new();
|
let mut res = BTreeMap::new();
|
||||||
for package in crate::db::DatabaseModel::new()
|
for package in crate::db::DatabaseModel::new()
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ impl HasLoggedOutSessions {
|
|||||||
for session in logged_out_sessions {
|
for session in logged_out_sessions {
|
||||||
let session = session.as_logout_session_id();
|
let session = session.as_logout_session_id();
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"UPDATE session SET logged_out = CURRENT_TIMESTAMP WHERE id = ?",
|
"UPDATE session SET logged_out = CURRENT_TIMESTAMP WHERE id = $1",
|
||||||
session
|
session
|
||||||
)
|
)
|
||||||
.execute(&mut sqlx_conn)
|
.execute(&mut sqlx_conn)
|
||||||
@@ -68,7 +68,7 @@ impl HasValidSession {
|
|||||||
|
|
||||||
pub async fn from_session(session: &HashSessionToken, ctx: &RpcContext) -> Result<Self, Error> {
|
pub async fn from_session(session: &HashSessionToken, ctx: &RpcContext) -> Result<Self, Error> {
|
||||||
let session_hash = session.hashed();
|
let session_hash = session.hashed();
|
||||||
let session = sqlx::query!("UPDATE session SET last_active = CURRENT_TIMESTAMP WHERE id = ? AND logged_out IS NULL OR logged_out > CURRENT_TIMESTAMP", session_hash)
|
let session = sqlx::query!("UPDATE session SET last_active = CURRENT_TIMESTAMP WHERE id = $1 AND logged_out IS NULL OR logged_out > CURRENT_TIMESTAMP", session_hash)
|
||||||
.execute(&mut ctx.secret_store.acquire().await?)
|
.execute(&mut ctx.secret_store.acquire().await?)
|
||||||
.await?;
|
.await?;
|
||||||
if session.rows_affected() == 0 {
|
if session.rows_affected() == 0 {
|
||||||
|
|||||||
7
backend/src/migrate.load
Normal file
7
backend/src/migrate.load
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
load database
|
||||||
|
from sqlite://{sqlite_path}
|
||||||
|
into postgresql://root@unix:/var/run/postgresql:5432/secrets
|
||||||
|
|
||||||
|
with include no drop, truncate, reset sequences, data only
|
||||||
|
|
||||||
|
excluding table names like '_sqlx_migrations';
|
||||||
@@ -6,7 +6,7 @@ use indexmap::IndexSet;
|
|||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
pub use models::InterfaceId;
|
pub use models::InterfaceId;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use torut::onion::TorSecretKeyV3;
|
use torut::onion::TorSecretKeyV3;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ impl Interfaces {
|
|||||||
package_id: &PackageId,
|
package_id: &PackageId,
|
||||||
) -> Result<InterfaceAddressMap, Error>
|
) -> Result<InterfaceAddressMap, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let mut interface_addresses = InterfaceAddressMap(BTreeMap::new());
|
let mut interface_addresses = InterfaceAddressMap(BTreeMap::new());
|
||||||
for (id, iface) in &self.0 {
|
for (id, iface) in &self.0 {
|
||||||
@@ -51,7 +51,7 @@ impl Interfaces {
|
|||||||
let key = TorSecretKeyV3::generate();
|
let key = TorSecretKeyV3::generate();
|
||||||
let key_vec = key.as_bytes().to_vec();
|
let key_vec = key.as_bytes().to_vec();
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT OR IGNORE INTO tor (package, interface, key) VALUES (?, ?, ?)",
|
"INSERT INTO tor (package, interface, key) VALUES ($1, $2, $3) ON CONFLICT (package, interface) DO NOTHING",
|
||||||
**package_id,
|
**package_id,
|
||||||
**id,
|
**id,
|
||||||
key_vec,
|
key_vec,
|
||||||
@@ -59,7 +59,7 @@ impl Interfaces {
|
|||||||
.execute(&mut *secrets)
|
.execute(&mut *secrets)
|
||||||
.await?;
|
.await?;
|
||||||
let key_row = sqlx::query!(
|
let key_row = sqlx::query!(
|
||||||
"SELECT key FROM tor WHERE package = ? AND interface = ?",
|
"SELECT key FROM tor WHERE package = $1 AND interface = $2",
|
||||||
**package_id,
|
**package_id,
|
||||||
**id,
|
**id,
|
||||||
)
|
)
|
||||||
@@ -89,10 +89,10 @@ impl Interfaces {
|
|||||||
package_id: &PackageId,
|
package_id: &PackageId,
|
||||||
) -> Result<BTreeMap<InterfaceId, TorSecretKeyV3>, Error>
|
) -> Result<BTreeMap<InterfaceId, TorSecretKeyV3>, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
Ok(sqlx::query!(
|
Ok(sqlx::query!(
|
||||||
"SELECT interface, key FROM tor WHERE package = ?",
|
"SELECT interface, key FROM tor WHERE package = $1",
|
||||||
**package_id
|
**package_id
|
||||||
)
|
)
|
||||||
.fetch_many(secrets)
|
.fetch_many(secrets)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::path::PathBuf;
|
|||||||
use openssl::pkey::{PKey, Private};
|
use openssl::pkey::{PKey, Private};
|
||||||
use openssl::x509::X509;
|
use openssl::x509::X509;
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::PgPool;
|
||||||
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ impl NetController {
|
|||||||
embassyd_tor_key: TorSecretKeyV3,
|
embassyd_tor_key: TorSecretKeyV3,
|
||||||
tor_control: SocketAddr,
|
tor_control: SocketAddr,
|
||||||
dns_bind: &[SocketAddr],
|
dns_bind: &[SocketAddr],
|
||||||
db: SqlitePool,
|
db: PgPool,
|
||||||
import_root_ca: Option<(PKey<Private>, X509)>,
|
import_root_ca: Option<(PKey<Private>, X509)>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let ssl = match import_root_ca {
|
let ssl = match import_root_ca {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use openssl::nid::Nid;
|
|||||||
use openssl::pkey::{PKey, Private};
|
use openssl::pkey::{PKey, Private};
|
||||||
use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509};
|
use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509};
|
||||||
use openssl::*;
|
use openssl::*;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::PgPool;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
@@ -33,17 +33,17 @@ pub struct SslManager {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SslStore {
|
struct SslStore {
|
||||||
secret_store: SqlitePool,
|
secret_store: PgPool,
|
||||||
}
|
}
|
||||||
impl SslStore {
|
impl SslStore {
|
||||||
fn new(db: SqlitePool) -> Result<Self, Error> {
|
fn new(db: PgPool) -> Result<Self, Error> {
|
||||||
Ok(SslStore { secret_store: db })
|
Ok(SslStore { secret_store: db })
|
||||||
}
|
}
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
async fn save_root_certificate(&self, key: &PKey<Private>, cert: &X509) -> Result<(), Error> {
|
async fn save_root_certificate(&self, key: &PKey<Private>, cert: &X509) -> Result<(), Error> {
|
||||||
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
||||||
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
||||||
let _n = sqlx::query!("INSERT INTO certificates (id, priv_key_pem, certificate_pem, lookup_string, created_at, updated_at) VALUES (0, ?, ?, NULL, datetime('now'), datetime('now'))", key_str, cert_str).execute(&self.secret_store).await?;
|
let _n = sqlx::query!("INSERT INTO certificates (id, priv_key_pem, certificate_pem, lookup_string, created_at, updated_at) VALUES (0, $1, $2, NULL, now(), now())", key_str, cert_str).execute(&self.secret_store).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
@@ -69,7 +69,7 @@ impl SslStore {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
||||||
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
||||||
let _n = sqlx::query!("INSERT INTO certificates (id, priv_key_pem, certificate_pem, lookup_string, created_at, updated_at) VALUES (1, ?, ?, NULL, datetime('now'), datetime('now'))", key_str, cert_str).execute(&self.secret_store).await?;
|
let _n = sqlx::query!("INSERT INTO certificates (id, priv_key_pem, certificate_pem, lookup_string, created_at, updated_at) VALUES (1, $1, $2, NULL, now(), now())", key_str, cert_str).execute(&self.secret_store).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn load_intermediate_certificate(&self) -> Result<Option<(PKey<Private>, X509)>, Error> {
|
async fn load_intermediate_certificate(&self) -> Result<Option<(PKey<Private>, X509)>, Error> {
|
||||||
@@ -108,7 +108,7 @@ impl SslStore {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
||||||
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
||||||
let _n = sqlx::query!("INSERT INTO certificates (priv_key_pem, certificate_pem, lookup_string, created_at, updated_at) VALUES (?, ?, ?, datetime('now'), datetime('now'))", key_str, cert_str, lookup_string).execute(&self.secret_store).await?;
|
let _n = sqlx::query!("INSERT INTO certificates (priv_key_pem, certificate_pem, lookup_string, created_at, updated_at) VALUES ($1, $2, $3, now(), now())", key_str, cert_str, lookup_string).execute(&self.secret_store).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn load_certificate(
|
async fn load_certificate(
|
||||||
@@ -116,7 +116,7 @@ impl SslStore {
|
|||||||
lookup_string: &str,
|
lookup_string: &str,
|
||||||
) -> Result<Option<(PKey<Private>, X509)>, Error> {
|
) -> Result<Option<(PKey<Private>, X509)>, Error> {
|
||||||
let m_row = sqlx::query!(
|
let m_row = sqlx::query!(
|
||||||
"SELECT priv_key_pem, certificate_pem FROM certificates WHERE lookup_string = ?",
|
"SELECT priv_key_pem, certificate_pem FROM certificates WHERE lookup_string = $1",
|
||||||
lookup_string
|
lookup_string
|
||||||
)
|
)
|
||||||
.fetch_optional(&self.secret_store)
|
.fetch_optional(&self.secret_store)
|
||||||
@@ -139,7 +139,8 @@ impl SslStore {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
let key_str = String::from_utf8(key.private_key_to_pem_pkcs8()?)?;
|
||||||
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
let cert_str = String::from_utf8(cert.to_pem()?)?;
|
||||||
let n = sqlx::query!("UPDATE certificates SET priv_key_pem = ?, certificate_pem = ?, updated_at = datetime('now') WHERE lookup_string = ?", key_str, cert_str, lookup_string).execute(&self.secret_store).await?;
|
let n = sqlx::query!("UPDATE certificates SET priv_key_pem = $1, certificate_pem = $2, updated_at = now() WHERE lookup_string = $3", key_str, cert_str, lookup_string)
|
||||||
|
.execute(&self.secret_store).await?;
|
||||||
if n.rows_affected() == 0 {
|
if n.rows_affected() == 0 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
eyre!(
|
eyre!(
|
||||||
@@ -161,7 +162,7 @@ lazy_static::lazy_static! {
|
|||||||
|
|
||||||
impl SslManager {
|
impl SslManager {
|
||||||
#[instrument(skip(db))]
|
#[instrument(skip(db))]
|
||||||
pub async fn init(db: SqlitePool) -> Result<Self, Error> {
|
pub async fn init(db: PgPool) -> Result<Self, Error> {
|
||||||
let store = SslStore::new(db)?;
|
let store = SslStore::new(db)?;
|
||||||
let (root_key, root_cert) = match store.load_root_certificate().await? {
|
let (root_key, root_cert) = match store.load_root_certificate().await? {
|
||||||
None => {
|
None => {
|
||||||
@@ -204,6 +205,10 @@ impl SslManager {
|
|||||||
}
|
}
|
||||||
Some((key, cert)) => Ok((key, cert)),
|
Some((key, cert)) => Ok((key, cert)),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
sqlx::query!("SELECT setval('certificates_id_seq', GREATEST(MAX(id) + 1, nextval('certificates_id_seq') - 1)) FROM certificates")
|
||||||
|
.fetch_one(&store.secret_store).await?;
|
||||||
|
|
||||||
Ok(SslManager {
|
Ok(SslManager {
|
||||||
store,
|
store,
|
||||||
root_cert,
|
root_cert,
|
||||||
@@ -221,7 +226,7 @@ impl SslManager {
|
|||||||
// the intermediate certificate
|
// the intermediate certificate
|
||||||
#[instrument(skip(db))]
|
#[instrument(skip(db))]
|
||||||
pub async fn import_root_ca(
|
pub async fn import_root_ca(
|
||||||
db: SqlitePool,
|
db: PgPool,
|
||||||
root_key: PKey<Private>,
|
root_key: PKey<Private>,
|
||||||
root_cert: X509,
|
root_cert: X509,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
@@ -508,10 +513,11 @@ fn make_leaf_cert(
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ca_details_persist() -> Result<(), Error> {
|
async fn ca_details_persist() -> Result<(), Error> {
|
||||||
let pool = sqlx::Pool::<sqlx::Sqlite>::connect("sqlite::memory:").await?;
|
let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
|
||||||
sqlx::query_file!("migrations/20210629193146_Init.sql")
|
sqlx::migrate!()
|
||||||
.execute(&pool)
|
.run(&pool)
|
||||||
.await?;
|
.await
|
||||||
|
.with_kind(crate::ErrorKind::Database)?;
|
||||||
let mgr = SslManager::init(pool.clone()).await?;
|
let mgr = SslManager::init(pool.clone()).await?;
|
||||||
let root_cert0 = mgr.root_cert;
|
let root_cert0 = mgr.root_cert;
|
||||||
let int_key0 = mgr.int_key;
|
let int_key0 = mgr.int_key;
|
||||||
@@ -532,10 +538,11 @@ async fn ca_details_persist() -> Result<(), Error> {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn certificate_details_persist() -> Result<(), Error> {
|
async fn certificate_details_persist() -> Result<(), Error> {
|
||||||
let pool = sqlx::Pool::<sqlx::Sqlite>::connect("sqlite::memory:").await?;
|
let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
|
||||||
sqlx::query_file!("migrations/20210629193146_Init.sql")
|
sqlx::migrate!()
|
||||||
.execute(&pool)
|
.run(&pool)
|
||||||
.await?;
|
.await
|
||||||
|
.with_kind(crate::ErrorKind::Database)?;
|
||||||
let mgr = SslManager::init(pool.clone()).await?;
|
let mgr = SslManager::init(pool.clone()).await?;
|
||||||
let package_id = "bitcoind".parse().unwrap();
|
let package_id = "bitcoind".parse().unwrap();
|
||||||
let (key0, cert_chain0) = mgr.certificate_for("start9", &package_id).await?;
|
let (key0, cert_chain0) = mgr.certificate_for("start9", &package_id).await?;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use futures::FutureExt;
|
|||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::{Executor, Sqlite};
|
use sqlx::{Executor, Postgres};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use torut::control::{AsyncEvent, AuthenticatedConn, ConnError};
|
use torut::control::{AsyncEvent, AuthenticatedConn, ConnError};
|
||||||
@@ -60,7 +60,7 @@ pub async fn list_services(
|
|||||||
#[instrument(skip(secrets))]
|
#[instrument(skip(secrets))]
|
||||||
pub async fn os_key<Ex>(secrets: &mut Ex) -> Result<TorSecretKeyV3, Error>
|
pub async fn os_key<Ex>(secrets: &mut Ex) -> Result<TorSecretKeyV3, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let key = sqlx::query!("SELECT tor_key FROM account")
|
let key = sqlx::query!("SELECT tor_key FROM account")
|
||||||
.fetch_one(secrets)
|
.fetch_one(secrets)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use chrono::{DateTime, Utc};
|
|||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use patch_db::{DbHandle, LockType};
|
use patch_db::{DbHandle, LockType};
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::PgPool;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ pub async fn notification() -> Result<(), Error> {
|
|||||||
#[instrument(skip(ctx))]
|
#[instrument(skip(ctx))]
|
||||||
pub async fn list(
|
pub async fn list(
|
||||||
#[context] ctx: RpcContext,
|
#[context] ctx: RpcContext,
|
||||||
#[arg] before: Option<u32>,
|
#[arg] before: Option<i32>,
|
||||||
#[arg] limit: Option<u32>,
|
#[arg] limit: Option<u32>,
|
||||||
) -> Result<WithRevision<Vec<Notification>>, Error> {
|
) -> Result<WithRevision<Vec<Notification>>, Error> {
|
||||||
let limit = limit.unwrap_or(40);
|
let limit = limit.unwrap_or(40);
|
||||||
@@ -39,8 +39,8 @@ pub async fn list(
|
|||||||
.unread_notification_count();
|
.unread_notification_count();
|
||||||
model.lock(&mut handle, LockType::Write).await?;
|
model.lock(&mut handle, LockType::Write).await?;
|
||||||
let records = sqlx::query!(
|
let records = sqlx::query!(
|
||||||
"SELECT id, package_id, created_at, code, level, title, message, data FROM notifications ORDER BY id DESC LIMIT ?",
|
"SELECT id, package_id, created_at, code, level, title, message, data FROM notifications ORDER BY id DESC LIMIT $1",
|
||||||
limit
|
limit as i64
|
||||||
).fetch_all(&ctx.secret_store).await?;
|
).fetch_all(&ctx.secret_store).await?;
|
||||||
let notifs = records
|
let notifs = records
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -80,9 +80,9 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
Some(before) => {
|
Some(before) => {
|
||||||
let records = sqlx::query!(
|
let records = sqlx::query!(
|
||||||
"SELECT id, package_id, created_at, code, level, title, message, data FROM notifications WHERE id < ? ORDER BY id DESC LIMIT ?",
|
"SELECT id, package_id, created_at, code, level, title, message, data FROM notifications WHERE id < $1 ORDER BY id DESC LIMIT $2",
|
||||||
before,
|
before,
|
||||||
limit
|
limit as i64
|
||||||
).fetch_all(&ctx.secret_store).await?;
|
).fetch_all(&ctx.secret_store).await?;
|
||||||
let res = records
|
let res = records
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -122,16 +122,16 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[command(display(display_none))]
|
#[command(display(display_none))]
|
||||||
pub async fn delete(#[context] ctx: RpcContext, #[arg] id: u32) -> Result<(), Error> {
|
pub async fn delete(#[context] ctx: RpcContext, #[arg] id: i32) -> Result<(), Error> {
|
||||||
sqlx::query!("DELETE FROM notifications WHERE id = ?", id)
|
sqlx::query!("DELETE FROM notifications WHERE id = $1", id)
|
||||||
.execute(&ctx.secret_store)
|
.execute(&ctx.secret_store)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command(rename = "delete-before", display(display_none))]
|
#[command(rename = "delete-before", display(display_none))]
|
||||||
pub async fn delete_before(#[context] ctx: RpcContext, #[arg] before: u32) -> Result<(), Error> {
|
pub async fn delete_before(#[context] ctx: RpcContext, #[arg] before: i32) -> Result<(), Error> {
|
||||||
sqlx::query!("DELETE FROM notifications WHERE id < ?", before)
|
sqlx::query!("DELETE FROM notifications WHERE id < $1", before)
|
||||||
.execute(&ctx.secret_store)
|
.execute(&ctx.secret_store)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -218,22 +218,22 @@ pub struct Notification {
|
|||||||
pub trait NotificationType:
|
pub trait NotificationType:
|
||||||
serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug
|
serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug
|
||||||
{
|
{
|
||||||
const CODE: u32;
|
const CODE: i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotificationType for () {
|
impl NotificationType for () {
|
||||||
const CODE: u32 = 0;
|
const CODE: i32 = 0;
|
||||||
}
|
}
|
||||||
impl NotificationType for BackupReport {
|
impl NotificationType for BackupReport {
|
||||||
const CODE: u32 = 1;
|
const CODE: i32 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NotificationManager {
|
pub struct NotificationManager {
|
||||||
sqlite: SqlitePool,
|
sqlite: PgPool,
|
||||||
cache: Mutex<HashMap<(Option<PackageId>, NotificationLevel, String), i64>>,
|
cache: Mutex<HashMap<(Option<PackageId>, NotificationLevel, String), i64>>,
|
||||||
}
|
}
|
||||||
impl NotificationManager {
|
impl NotificationManager {
|
||||||
pub fn new(sqlite: SqlitePool) -> Self {
|
pub fn new(sqlite: PgPool) -> Self {
|
||||||
NotificationManager {
|
NotificationManager {
|
||||||
sqlite,
|
sqlite,
|
||||||
cache: Mutex::new(HashMap::new()),
|
cache: Mutex::new(HashMap::new()),
|
||||||
@@ -267,9 +267,9 @@ impl NotificationManager {
|
|||||||
let sql_data =
|
let sql_data =
|
||||||
serde_json::to_string(&subtype).with_kind(crate::ErrorKind::Serialization)?;
|
serde_json::to_string(&subtype).with_kind(crate::ErrorKind::Serialization)?;
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO notifications (package_id, code, level, title, message, data) VALUES (?, ?, ?, ?, ?, ?)",
|
"INSERT INTO notifications (package_id, code, level, title, message, data) VALUES ($1, $2, $3, $4, $5, $6)",
|
||||||
sql_package_id,
|
sql_package_id,
|
||||||
sql_code,
|
sql_code as i32,
|
||||||
sql_level,
|
sql_level,
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use rpc_toolkit::command;
|
|||||||
use rpc_toolkit::yajrc::RpcError;
|
use rpc_toolkit::yajrc::RpcError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use sqlx::{Connection, Executor, Sqlite};
|
use sqlx::{Connection, Executor, Postgres};
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
||||||
@@ -52,7 +52,7 @@ use crate::{ensure_code, Error, ErrorKind, ResultExt};
|
|||||||
#[instrument(skip(secrets))]
|
#[instrument(skip(secrets))]
|
||||||
pub async fn password_hash<Ex>(secrets: &mut Ex) -> Result<String, Error>
|
pub async fn password_hash<Ex>(secrets: &mut Ex) -> Result<String, Error>
|
||||||
where
|
where
|
||||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
for<'a> &'a mut Ex: Executor<'a, Database = Postgres>,
|
||||||
{
|
{
|
||||||
let password = sqlx::query!("SELECT password FROM account")
|
let password = sqlx::query!("SELECT password FROM account")
|
||||||
.fetch_one(secrets)
|
.fetch_one(secrets)
|
||||||
@@ -448,7 +448,7 @@ async fn fresh_setup(
|
|||||||
let key_vec = tor_key.as_bytes().to_vec();
|
let key_vec = tor_key.as_bytes().to_vec();
|
||||||
let sqlite_pool = ctx.secret_store().await?;
|
let sqlite_pool = ctx.secret_store().await?;
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"REPLACE INTO account (id, password, tor_key) VALUES (?, ?, ?)",
|
"INSERT INTO account (id, password, tor_key) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET password = $2, tor_key = $3",
|
||||||
0,
|
0,
|
||||||
password,
|
password,
|
||||||
key_vec,
|
key_vec,
|
||||||
@@ -696,7 +696,7 @@ async fn recover_v2(
|
|||||||
.with_kind(crate::ErrorKind::PasswordHashGeneration)?;
|
.with_kind(crate::ErrorKind::PasswordHashGeneration)?;
|
||||||
let sqlite_pool = ctx.secret_store().await?;
|
let sqlite_pool = ctx.secret_store().await?;
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"REPLACE INTO account (id, password, tor_key) VALUES (?, ?, ?)",
|
"INSERT INTO account (id, password, tor_key) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET password = $2, tor_key = $3",
|
||||||
0,
|
0,
|
||||||
password,
|
password,
|
||||||
key_vec
|
key_vec
|
||||||
@@ -790,7 +790,7 @@ async fn recover_v2(
|
|||||||
);
|
);
|
||||||
let key_vec = key_vec[32..].to_vec();
|
let key_vec = key_vec[32..].to_vec();
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"REPLACE INTO tor (package, interface, key) VALUES (?, 'main', ?)",
|
"INSERT INTO tor (package, interface, key) VALUES ($1, 'main', $2) ON CONFLICT (package, interface) DO UPDATE SET key = $2",
|
||||||
*dst_id,
|
*dst_id,
|
||||||
key_vec,
|
key_vec,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use chrono::Utc;
|
|||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::context::RpcContext;
|
use crate::context::RpcContext;
|
||||||
@@ -61,7 +61,7 @@ pub async fn add(#[context] ctx: RpcContext, #[arg] key: PubKey) -> Result<SshKe
|
|||||||
let pool = &ctx.secret_store;
|
let pool = &ctx.secret_store;
|
||||||
// check fingerprint for duplicates
|
// check fingerprint for duplicates
|
||||||
let fp = key.0.fingerprint_md5();
|
let fp = key.0.fingerprint_md5();
|
||||||
match sqlx::query!("SELECT * FROM ssh_keys WHERE fingerprint = ?", fp)
|
match sqlx::query!("SELECT * FROM ssh_keys WHERE fingerprint = $1", fp)
|
||||||
.fetch_optional(pool)
|
.fetch_optional(pool)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
@@ -70,7 +70,7 @@ pub async fn add(#[context] ctx: RpcContext, #[arg] key: PubKey) -> Result<SshKe
|
|||||||
let raw_key = format!("{}", key.0);
|
let raw_key = format!("{}", key.0);
|
||||||
let created_at = Utc::now().to_rfc3339();
|
let created_at = Utc::now().to_rfc3339();
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO ssh_keys (fingerprint, openssh_pubkey, created_at) VALUES (?, ?, ?)",
|
"INSERT INTO ssh_keys (fingerprint, openssh_pubkey, created_at) VALUES ($1, $2, $3)",
|
||||||
fp,
|
fp,
|
||||||
raw_key,
|
raw_key,
|
||||||
created_at
|
created_at
|
||||||
@@ -96,7 +96,7 @@ pub async fn delete(#[context] ctx: RpcContext, #[arg] fingerprint: String) -> R
|
|||||||
let pool = &ctx.secret_store;
|
let pool = &ctx.secret_store;
|
||||||
// check if fingerprint is in DB
|
// check if fingerprint is in DB
|
||||||
// if in DB, remove it from DB
|
// if in DB, remove it from DB
|
||||||
let n = sqlx::query!("DELETE FROM ssh_keys WHERE fingerprint = ?", fingerprint)
|
let n = sqlx::query!("DELETE FROM ssh_keys WHERE fingerprint = $1", fingerprint)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await?
|
.await?
|
||||||
.rows_affected();
|
.rows_affected();
|
||||||
@@ -172,7 +172,10 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(pool, dest))]
|
#[instrument(skip(pool, dest))]
|
||||||
pub async fn sync_keys_from_db<P: AsRef<Path>>(pool: &Pool<Sqlite>, dest: P) -> Result<(), Error> {
|
pub async fn sync_keys_from_db<P: AsRef<Path>>(
|
||||||
|
pool: &Pool<Postgres>,
|
||||||
|
dest: P,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let dest = dest.as_ref();
|
let dest = dest.as_ref();
|
||||||
let keys = sqlx::query!("SELECT openssh_pubkey FROM ssh_keys")
|
let keys = sqlx::query!("SELECT openssh_pubkey FROM ssh_keys")
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ pub async fn kernel_logs_nofollow(
|
|||||||
_ctx: (),
|
_ctx: (),
|
||||||
(limit, cursor, before, _): (Option<usize>, Option<String>, bool, bool),
|
(limit, cursor, before, _): (Option<usize>, Option<String>, bool, bool),
|
||||||
) -> Result<LogResponse, Error> {
|
) -> Result<LogResponse, Error> {
|
||||||
fetch_logs(LogSource::Service(SYSTEMD_UNIT), limit, cursor, before).await
|
fetch_logs(LogSource::Kernel, limit, cursor, before).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command(rpc_only, rename = "follow", display(display_none))]
|
#[command(rpc_only, rename = "follow", display(display_none))]
|
||||||
@@ -120,7 +120,7 @@ pub async fn kernel_logs_follow(
|
|||||||
#[context] ctx: RpcContext,
|
#[context] ctx: RpcContext,
|
||||||
#[parent_data] (limit, _, _, _): (Option<usize>, Option<String>, bool, bool),
|
#[parent_data] (limit, _, _, _): (Option<usize>, Option<String>, bool, bool),
|
||||||
) -> Result<LogFollowResponse, Error> {
|
) -> Result<LogFollowResponse, Error> {
|
||||||
follow_logs(ctx, LogSource::Service(SYSTEMD_UNIT), limit).await
|
follow_logs(ctx, LogSource::Kernel, limit).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|||||||
22
backend/update-sqlx-data.sh
Executable file
22
backend/update-sqlx-data.sh
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
mkdir $TMP_DIR/pgdata
|
||||||
|
docker run -d --rm --name=tmp_postgres -e POSTGRES_PASSWORD=password -v $TMP_DIR/pgdata:/var/lib/postgresql/data postgres
|
||||||
|
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
ctr=0
|
||||||
|
while ! docker exec tmp_postgres psql -U postgres || [ $ctr -lt 5 ]; do
|
||||||
|
ctr=$[ctr + 1]
|
||||||
|
sleep 1;
|
||||||
|
done
|
||||||
|
|
||||||
|
PG_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' tmp_postgres)
|
||||||
|
|
||||||
|
DATABASE_URL=postgres://postgres:password@$PG_IP/postgres cargo sqlx migrate run
|
||||||
|
DATABASE_URL=postgres://postgres:password@$PG_IP/postgres cargo sqlx prepare -- --lib --profile=test
|
||||||
|
)
|
||||||
|
|
||||||
|
docker stop tmp_postgres
|
||||||
|
sudo rm -rf $TMP_DIR
|
||||||
@@ -13,6 +13,12 @@ fi
|
|||||||
|
|
||||||
passwd -l start9
|
passwd -l start9
|
||||||
|
|
||||||
|
while ! ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3` > /dev/null; do
|
||||||
|
>&2 echo "Waiting for internet connection..."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Connected to network"
|
||||||
|
|
||||||
# change timezone
|
# change timezone
|
||||||
timedatectl set-timezone Etc/UTC
|
timedatectl set-timezone Etc/UTC
|
||||||
|
|
||||||
@@ -45,7 +51,9 @@ apt-get install -y \
|
|||||||
network-manager \
|
network-manager \
|
||||||
vim \
|
vim \
|
||||||
jq \
|
jq \
|
||||||
ncdu
|
ncdu \
|
||||||
|
postgresql \
|
||||||
|
pgloader
|
||||||
|
|
||||||
# Setup repository from The Guardian Project and install latest stable Tor daemon
|
# Setup repository from The Guardian Project and install latest stable Tor daemon
|
||||||
touch /etc/apt/sources.list.d/tor.list
|
touch /etc/apt/sources.list.d/tor.list
|
||||||
@@ -64,6 +72,10 @@ systemctl start systemd-resolved
|
|||||||
apt-get remove --purge openresolv dhcpcd5 -y
|
apt-get remove --purge openresolv dhcpcd5 -y
|
||||||
systemctl disable wpa_supplicant.service
|
systemctl disable wpa_supplicant.service
|
||||||
|
|
||||||
|
sudo -u postgres createuser root
|
||||||
|
sudo -u postgres createdb secrets -O root
|
||||||
|
systemctl disable postgresql.service
|
||||||
|
|
||||||
ln -rsf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
|
ln -rsf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
|
||||||
|
|
||||||
systemctl disable bluetooth.service
|
systemctl disable bluetooth.service
|
||||||
|
|||||||
Reference in New Issue
Block a user