Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/docker-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
schedule:
# every midnight
- cron: "0 0 * * *"
workflow_dispatch:

jobs:
build-n-release-docker-nightly:
Expand Down
2 changes: 1 addition & 1 deletion compose.base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ services:
healthcheck:
# TODO The healthcheck performance is dependent on the lifetime of the
# application. With more devices it could get slower.
test: [ "CMD-SHELL", "meesign-server get-devices"]
test: [ "CMD-SHELL", "meesign-server --ca-cert-path /meesign/keys/meesign-ca-cert.pem get-devices"]
interval: 1s
timeout: 5s
retries: 10
96 changes: 96 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
description = "MeeSign Server";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
flake-utils.url = "github:numtide/flake-utils";
};

outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
nativeDependencies = with pkgs; [
libpq
pkg-config
jdk17
rust-bin.beta.latest.default
protobuf
];
buildDependencies = with pkgs; [
openssl
];
meesign-server = pkgs.callPackage ./default.nix { };
in
with pkgs;
{
devShells.default = mkShell {
buildInputs = buildDependencies ++ nativeDependencies;
};

packages = {
inherit meesign-server;
default = meesign-server;
};
}
);
}
31 changes: 12 additions & 19 deletions src/interfaces/grpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,9 @@ fn validate_jwt(token: &str) -> Result<Vec<u8>, Status> {
validation.required_spec_claims.clear();
validation.validate_exp = false;

let token_data = decode::<JwtClaims>(
token,
&DecodingKey::from_secret(&JWT_SECRET),
&validation,
)
.map_err(|_| Status::unauthenticated("Invalid authentication token"))?;
let token_data =
decode::<JwtClaims>(token, &DecodingKey::from_secret(&JWT_SECRET), &validation)
.map_err(|_| Status::unauthenticated("Invalid authentication token"))?;

hex::decode(&token_data.claims.sub)
.map_err(|_| Status::unauthenticated("Invalid device ID in token"))
Expand Down Expand Up @@ -116,11 +113,7 @@ impl MeeSignService {

/// Check client authentication using either mTLS peer certs or JWT token.
/// Returns Ok(()) if auth passes or is not required.
fn check_client_auth<T>(
&self,
request: &Request<T>,
required: bool,
) -> Result<(), Status> {
fn check_client_auth<T>(&self, request: &Request<T>, required: bool) -> Result<(), Status> {
if let Some(device_id) = extract_device_id(request) {
if !self.state.device_exists(&device_id) {
return Err(Status::unauthenticated("Unknown device"));
Expand Down Expand Up @@ -252,8 +245,8 @@ impl MeeSign for MeeSignService {
) -> Result<Response<msg::Resp>, Status> {
self.check_client_auth(&request, true)?;

let device_id = extract_device_id(&request)
.expect("device_id must be present after auth check");
let device_id =
extract_device_id(&request).expect("device_id must be present after auth check");

let request = request.into_inner();
let task_id = Uuid::from_slice(&request.task).unwrap();
Expand Down Expand Up @@ -462,8 +455,8 @@ impl MeeSign for MeeSignService {
) -> Result<Response<msg::Resp>, Status> {
self.check_client_auth(&request, true)?;

let device_id = extract_device_id(&request)
.expect("device_id must be present after auth check");
let device_id =
extract_device_id(&request).expect("device_id must be present after auth check");

let request = request.into_inner();
let task_id = Uuid::from_slice(&request.task).unwrap();
Expand Down Expand Up @@ -497,8 +490,8 @@ impl MeeSign for MeeSignService {
) -> Result<Response<msg::Resp>, Status> {
self.check_client_auth(&request, true)?;

let device_id = extract_device_id(&request)
.expect("device_id must be present after auth check");
let device_id =
extract_device_id(&request).expect("device_id must be present after auth check");

let task_id = request.into_inner().task_id;

Expand Down Expand Up @@ -531,8 +524,8 @@ impl MeeSign for MeeSignService {
) -> Result<Response<Self::SubscribeUpdatesStream>, Status> {
self.check_client_auth(&request, true)?;

let device_id = extract_device_id(&request)
.expect("device_id must be present after auth check");
let device_id =
extract_device_id(&request).expect("device_id must be present after auth check");

let (tx, rx) = mpsc::channel(8);

Expand Down
30 changes: 22 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ struct Args {
#[clap(short, long, default_value_t = String::from("meesign.local"))]
host: String,

#[clap(
short,
long,
help = "The filepath to the X509 CA certificate to be used to verify server's TLS certificate, defaults to system's CA roots."
)]
ca_cert_path: Option<String>,

#[cfg(feature = "cli")]
#[clap(subcommand)]
command: Option<cli::Commands>,
Expand Down Expand Up @@ -252,8 +259,9 @@ async fn main() -> Result<(), String> {
mod cli {
use crate::proto::KeyType;
use crate::proto::MeeSignClient;
use crate::{Args, CA_CERT};
use crate::{Args};
use clap::Subcommand;
use openssl::x509::X509;
use std::str::FromStr;
use std::time::SystemTime;
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Uri};
Expand Down Expand Up @@ -293,13 +301,19 @@ mod cli {

pub(super) async fn handle_command(args: Args) -> Result<(), String> {
if let Some(command) = args.command {
let tls = ClientTlsConfig::new()
.domain_name(&args.host)
.ca_certificate(Certificate::from_pem(
CA_CERT
.to_pem()
.map_err(|_| "Unable to load CA certificate".to_string())?,
));
let tls = match &args.ca_cert_path {
Some(filepath) => {
let ca_cert: X509 = X509::from_pem(&std::fs::read(filepath).unwrap()).unwrap();
ClientTlsConfig::new()
.domain_name(&args.host)
.ca_certificate(Certificate::from_pem(
ca_cert
.to_pem()
.map_err(|_| "Unable to load CA certificate".to_string())?,
))
}
None => ClientTlsConfig::new().domain_name(&args.host),
};

let channel = Channel::builder(
Uri::from_str(&format!("https://{}:{}", &args.host, args.port))
Expand Down
Loading