mirror of
https://codeberg.org/icewind/nextcloud-config-parser.git
synced 2026-06-03 16:44:09 +02:00
improve handling of mysql ssl options
This commit is contained in:
parent
d154bdd9f0
commit
4b8c9530fb
6 changed files with 226 additions and 20 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nextcloud-config-parser"
|
name = "nextcloud-config-parser"
|
||||||
description = "Rust parser for nextcloud config files"
|
description = "Rust parser for nextcloud config files"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
|
||||||
37
src/lib.rs
37
src/lib.rs
|
|
@ -127,6 +127,18 @@ pub enum NotAConfigError {
|
||||||
NotAnArray(PathBuf),
|
NotAnArray(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SslOptions {
|
||||||
|
Enabled {
|
||||||
|
key: String,
|
||||||
|
cert: String,
|
||||||
|
ca: String,
|
||||||
|
verify: bool,
|
||||||
|
},
|
||||||
|
Disabled,
|
||||||
|
Default,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Database {
|
pub enum Database {
|
||||||
Sqlite {
|
Sqlite {
|
||||||
|
|
@ -137,14 +149,14 @@ pub enum Database {
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
connect: DbConnect,
|
connect: DbConnect,
|
||||||
disable_ssl: bool,
|
ssl_options: SslOptions,
|
||||||
},
|
},
|
||||||
Postgres {
|
Postgres {
|
||||||
database: String,
|
database: String,
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
connect: DbConnect,
|
connect: DbConnect,
|
||||||
disable_ssl: bool,
|
ssl_options: SslOptions,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,14 +184,25 @@ impl From<Database> for sqlx::any::AnyConnectOptions {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
connect,
|
connect,
|
||||||
disable_ssl,
|
ssl_options,
|
||||||
} => {
|
} => {
|
||||||
let mut options = MySqlConnectOptions::default()
|
let mut options = MySqlConnectOptions::default()
|
||||||
.database(&database)
|
.database(&database)
|
||||||
.username(&username)
|
.username(&username)
|
||||||
.password(&password);
|
.password(&password);
|
||||||
if disable_ssl {
|
match ssl_options {
|
||||||
options = options.ssl_mode(MySqlSslMode::Disabled);
|
SslOptions::Enabled { ca, verify, .. } => {
|
||||||
|
options = options.ssl_ca(ca);
|
||||||
|
options = options.ssl_mode(if verify {
|
||||||
|
MySqlSslMode::VerifyIdentity
|
||||||
|
} else {
|
||||||
|
MySqlSslMode::VerifyCa
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SslOptions::Disabled => {
|
||||||
|
options = options.ssl_mode(MySqlSslMode::Disabled);
|
||||||
|
}
|
||||||
|
SslOptions::Default => {}
|
||||||
}
|
}
|
||||||
match connect {
|
match connect {
|
||||||
DbConnect::Socket(socket) => {
|
DbConnect::Socket(socket) => {
|
||||||
|
|
@ -196,13 +219,13 @@ impl From<Database> for sqlx::any::AnyConnectOptions {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
connect,
|
connect,
|
||||||
disable_ssl,
|
ssl_options,
|
||||||
} => {
|
} => {
|
||||||
let mut options = PgConnectOptions::default()
|
let mut options = PgConnectOptions::default()
|
||||||
.database(&database)
|
.database(&database)
|
||||||
.username(&username)
|
.username(&username)
|
||||||
.password(&password);
|
.password(&password);
|
||||||
if disable_ssl {
|
if matches!(ssl_options, SslOptions::Disabled) {
|
||||||
options = options.ssl_mode(PgSslMode::Disable);
|
options = options.ssl_mode(PgSslMode::Disable);
|
||||||
}
|
}
|
||||||
match connect {
|
match connect {
|
||||||
|
|
|
||||||
147
src/nc.rs
147
src/nc.rs
|
|
@ -1,6 +1,8 @@
|
||||||
#[cfg(feature = "redis-connect")]
|
#[cfg(feature = "redis-connect")]
|
||||||
use crate::RedisConfig;
|
use crate::RedisConfig;
|
||||||
use crate::{Config, Database, DbConnect, DbError, Error, NotAConfigError, PhpParseError, Result};
|
use crate::{
|
||||||
|
Config, Database, DbConnect, DbError, Error, NotAConfigError, PhpParseError, Result, SslOptions,
|
||||||
|
};
|
||||||
use php_literal_parser::Value;
|
use php_literal_parser::Value;
|
||||||
#[cfg(feature = "redis-connect")]
|
#[cfg(feature = "redis-connect")]
|
||||||
use redis::{ConnectionAddr, ConnectionInfo, RedisConnectionInfo};
|
use redis::{ConnectionAddr, ConnectionInfo, RedisConnectionInfo};
|
||||||
|
|
@ -16,6 +18,10 @@ static CONFIG_CONSTANTS: &[(&str, &str)] = &[
|
||||||
(r"\RedisCluster::FAILOVER_ERROR", "1"),
|
(r"\RedisCluster::FAILOVER_ERROR", "1"),
|
||||||
(r"\RedisCluster::DISTRIBUTE", "2"),
|
(r"\RedisCluster::DISTRIBUTE", "2"),
|
||||||
(r"\RedisCluster::FAILOVER_DISTRIBUTE_SLAVES", "3"),
|
(r"\RedisCluster::FAILOVER_DISTRIBUTE_SLAVES", "3"),
|
||||||
|
(r"\PDO::MYSQL_ATTR_SSL_KEY", "1007"),
|
||||||
|
(r"\PDO::MYSQL_ATTR_SSL_CERT", "1008"),
|
||||||
|
(r"\PDO::MYSQL_ATTR_SSL_CA", "1009"),
|
||||||
|
(r"\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT", "1014"),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn glob_config_files(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
fn glob_config_files(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
||||||
|
|
@ -174,12 +180,35 @@ fn parse_db_options(parsed: &Value) -> Result<Database> {
|
||||||
}
|
}
|
||||||
let database = parsed["dbname"].as_str().ok_or(DbError::NoName)?;
|
let database = parsed["dbname"].as_str().ok_or(DbError::NoName)?;
|
||||||
|
|
||||||
|
let verify = parsed["dbdriveroptions"][1014] // MYSQL_ATTR_SSL_VERIFY_SERVER_CERT
|
||||||
|
.clone()
|
||||||
|
.into_bool()
|
||||||
|
.unwrap_or(true);
|
||||||
|
|
||||||
|
let ssl_options = if let (Some(ssl_key), Some(ssl_cert), Some(ssl_ca)) = (
|
||||||
|
parsed["dbdriveroptions"][1007].as_str(), // MYSQL_ATTR_SSL_KEY
|
||||||
|
parsed["dbdriveroptions"][1008].as_str(), // MYSQL_ATTR_SSL_CERT
|
||||||
|
parsed["dbdriveroptions"][1009].as_str(), // MYSQL_ATTR_SSL_CA
|
||||||
|
) {
|
||||||
|
SslOptions::Enabled {
|
||||||
|
key: ssl_key.into(),
|
||||||
|
cert: ssl_cert.into(),
|
||||||
|
ca: ssl_ca.into(),
|
||||||
|
verify,
|
||||||
|
}
|
||||||
|
// if MYSQL_ATTR_SSL_VERIFY_SERVER_CERT is disabled, we should be able to use ssl even with raw ip
|
||||||
|
} else if disable_ssl && verify {
|
||||||
|
SslOptions::Disabled
|
||||||
|
} else {
|
||||||
|
SslOptions::Default
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Database::MySql {
|
Ok(Database::MySql {
|
||||||
database: database.into(),
|
database: database.into(),
|
||||||
username: username.into(),
|
username: username.into(),
|
||||||
password: password.into(),
|
password: password.into(),
|
||||||
connect,
|
connect,
|
||||||
disable_ssl,
|
ssl_options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Some("pgsql") => {
|
Some("pgsql") => {
|
||||||
|
|
@ -228,12 +257,18 @@ fn parse_db_options(parsed: &Value) -> Result<Database> {
|
||||||
}
|
}
|
||||||
let database = parsed["dbname"].as_str().ok_or(DbError::NoName)?;
|
let database = parsed["dbname"].as_str().ok_or(DbError::NoName)?;
|
||||||
|
|
||||||
|
let ssl_options = if disable_ssl {
|
||||||
|
SslOptions::Disabled
|
||||||
|
} else {
|
||||||
|
SslOptions::Default
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Database::Postgres {
|
Ok(Database::Postgres {
|
||||||
database: database.into(),
|
database: database.into(),
|
||||||
username: username.into(),
|
username: username.into(),
|
||||||
password: password.into(),
|
password: password.into(),
|
||||||
connect,
|
connect,
|
||||||
disable_ssl,
|
ssl_options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Some("sqlite3") => {
|
Some("sqlite3") => {
|
||||||
|
|
@ -375,7 +410,7 @@ fn test_parse_config_basic() {
|
||||||
host: "127.0.0.1".to_string(),
|
host: "127.0.0.1".to_string(),
|
||||||
port: 3306,
|
port: 3306,
|
||||||
},
|
},
|
||||||
disable_ssl: true,
|
ssl_options: SslOptions::Disabled,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -444,7 +479,7 @@ fn test_parse_comment_whitespace() {
|
||||||
host: "127.0.0.1".to_string(),
|
host: "127.0.0.1".to_string(),
|
||||||
port: 3306,
|
port: 3306,
|
||||||
},
|
},
|
||||||
disable_ssl: true,
|
ssl_options: SslOptions::Disabled,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -475,7 +510,7 @@ fn test_parse_port_in_host() {
|
||||||
host: "127.0.0.1".to_string(),
|
host: "127.0.0.1".to_string(),
|
||||||
port: 1234,
|
port: 1234,
|
||||||
},
|
},
|
||||||
disable_ssl: true,
|
ssl_options: SslOptions::Disabled,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -498,7 +533,7 @@ fn test_parse_postgres_socket() {
|
||||||
username: "redacted".to_string(),
|
username: "redacted".to_string(),
|
||||||
password: "redacted".to_string(),
|
password: "redacted".to_string(),
|
||||||
connect: DbConnect::Socket("/var/run/postgresql".into()),
|
connect: DbConnect::Socket("/var/run/postgresql".into()),
|
||||||
disable_ssl: false,
|
ssl_options: SslOptions::Default,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -524,7 +559,7 @@ fn test_parse_postgres_socket_folder() {
|
||||||
username: "redacted".to_string(),
|
username: "redacted".to_string(),
|
||||||
password: "redacted".to_string(),
|
password: "redacted".to_string(),
|
||||||
connect: DbConnect::Socket("/var/run/postgresql".into()),
|
connect: DbConnect::Socket("/var/run/postgresql".into()),
|
||||||
disable_ssl: false,
|
ssl_options: SslOptions::Default,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -574,7 +609,7 @@ fn test_parse_config_multiple() {
|
||||||
host: "127.0.0.1".to_string(),
|
host: "127.0.0.1".to_string(),
|
||||||
port: 3306,
|
port: 3306,
|
||||||
},
|
},
|
||||||
disable_ssl: true,
|
ssl_options: SslOptions::Disabled,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -628,7 +663,7 @@ fn test_parse_config_mysql_fqdn() {
|
||||||
host: "db.example.com".to_string(),
|
host: "db.example.com".to_string(),
|
||||||
port: 3306,
|
port: 3306,
|
||||||
},
|
},
|
||||||
disable_ssl: false,
|
ssl_options: SslOptions::Default,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -642,6 +677,94 @@ fn test_parse_config_mysql_fqdn() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_config_mysql_ip_no_verify() {
|
||||||
|
let config = config_from_file("tests/configs/mysql_ip_no_verify.php");
|
||||||
|
assert_debug_equal(
|
||||||
|
&Database::MySql {
|
||||||
|
database: "nextcloud".to_string(),
|
||||||
|
username: "nextcloud".to_string(),
|
||||||
|
password: "secret".to_string(),
|
||||||
|
connect: DbConnect::Tcp {
|
||||||
|
host: "1.2.3.4".to_string(),
|
||||||
|
port: 3306,
|
||||||
|
},
|
||||||
|
ssl_options: SslOptions::Default,
|
||||||
|
},
|
||||||
|
&config.database,
|
||||||
|
);
|
||||||
|
#[cfg(feature = "db-sqlx")]
|
||||||
|
assert_debug_equal(
|
||||||
|
AnyConnectOptions::from_str(
|
||||||
|
"mysql://nextcloud:secret@1.2.3.4/nextcloud?ssl-mode=preferred",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
config.database.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_config_mysql_ssl_ca() {
|
||||||
|
let config = config_from_file("tests/configs/mysql_ssl_ca.php");
|
||||||
|
assert_debug_equal(
|
||||||
|
&Database::MySql {
|
||||||
|
database: "nextcloud".to_string(),
|
||||||
|
username: "nextcloud".to_string(),
|
||||||
|
password: "secret".to_string(),
|
||||||
|
connect: DbConnect::Tcp {
|
||||||
|
host: "db.example.com".to_string(),
|
||||||
|
port: 3306,
|
||||||
|
},
|
||||||
|
ssl_options: SslOptions::Enabled {
|
||||||
|
key: "/ssl-key.pem".into(),
|
||||||
|
cert: "/ssl-cert.pem".into(),
|
||||||
|
ca: "/ca-cert.pem".into(),
|
||||||
|
verify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&config.database,
|
||||||
|
);
|
||||||
|
#[cfg(feature = "db-sqlx")]
|
||||||
|
assert_debug_equal(
|
||||||
|
AnyConnectOptions::from_str(
|
||||||
|
"mysql://nextcloud:secret@db.example.com/nextcloud?ssl-mode=verify_identity&ssl-ca=/ca-cert.pem",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
config.database.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_config_mysql_ssl_ca_no_verify() {
|
||||||
|
let config = config_from_file("tests/configs/mysql_ssl_ca_no_verify.php");
|
||||||
|
assert_debug_equal(
|
||||||
|
&Database::MySql {
|
||||||
|
database: "nextcloud".to_string(),
|
||||||
|
username: "nextcloud".to_string(),
|
||||||
|
password: "secret".to_string(),
|
||||||
|
connect: DbConnect::Tcp {
|
||||||
|
host: "db.example.com".to_string(),
|
||||||
|
port: 3306,
|
||||||
|
},
|
||||||
|
ssl_options: SslOptions::Enabled {
|
||||||
|
key: "/ssl-key.pem".into(),
|
||||||
|
cert: "/ssl-cert.pem".into(),
|
||||||
|
ca: "/ca-cert.pem".into(),
|
||||||
|
verify: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&config.database,
|
||||||
|
);
|
||||||
|
#[cfg(feature = "db-sqlx")]
|
||||||
|
assert_debug_equal(
|
||||||
|
AnyConnectOptions::from_str(
|
||||||
|
"mysql://nextcloud:secret@db.example.com/nextcloud?ssl-mode=verify_ca&ssl-ca=/ca-cert.pem",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
config.database.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_postgres_ip() {
|
fn test_parse_postgres_ip() {
|
||||||
let config = config_from_file("tests/configs/postgres_ip.php");
|
let config = config_from_file("tests/configs/postgres_ip.php");
|
||||||
|
|
@ -654,7 +777,7 @@ fn test_parse_postgres_ip() {
|
||||||
host: "1.2.3.4".to_string(),
|
host: "1.2.3.4".to_string(),
|
||||||
port: 5432,
|
port: 5432,
|
||||||
},
|
},
|
||||||
disable_ssl: true,
|
ssl_options: SslOptions::Disabled,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
@ -684,7 +807,7 @@ fn test_parse_postgres_fqdn() {
|
||||||
host: "pg.example.com".to_string(),
|
host: "pg.example.com".to_string(),
|
||||||
port: 5432,
|
port: 5432,
|
||||||
},
|
},
|
||||||
disable_ssl: false,
|
ssl_options: SslOptions::Default,
|
||||||
},
|
},
|
||||||
&config.database,
|
&config.database,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
18
tests/configs/mysql_ip_no_verify.php
Normal file
18
tests/configs/mysql_ip_no_verify.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$CONFIG = [
|
||||||
|
'overwrite.cli.url' => 'https://cloud.example.com',
|
||||||
|
'dbtype' => 'mysql',
|
||||||
|
'dbname' => 'nextcloud',
|
||||||
|
'dbhost' => '1.2.3.4',
|
||||||
|
'dbport' => '',
|
||||||
|
'dbtableprefix' => 'oc_',
|
||||||
|
'dbuser' => 'nextcloud',
|
||||||
|
'dbpassword' => 'secret',
|
||||||
|
'redis' => [
|
||||||
|
'host' => 'localhost'
|
||||||
|
],
|
||||||
|
'dbdriveroptions' => [
|
||||||
|
\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
21
tests/configs/mysql_ssl_ca.php
Normal file
21
tests/configs/mysql_ssl_ca.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$CONFIG = [
|
||||||
|
'overwrite.cli.url' => 'https://cloud.example.com',
|
||||||
|
'dbtype' => 'mysql',
|
||||||
|
'dbname' => 'nextcloud',
|
||||||
|
'dbhost' => 'db.example.com',
|
||||||
|
'dbport' => '',
|
||||||
|
'dbtableprefix' => 'oc_',
|
||||||
|
'dbuser' => 'nextcloud',
|
||||||
|
'dbpassword' => 'secret',
|
||||||
|
'redis' => [
|
||||||
|
'host' => 'localhost'
|
||||||
|
],
|
||||||
|
'dbdriveroptions' => [
|
||||||
|
\PDO::MYSQL_ATTR_SSL_KEY => '/ssl-key.pem',
|
||||||
|
\PDO::MYSQL_ATTR_SSL_CERT => '/ssl-cert.pem',
|
||||||
|
\PDO::MYSQL_ATTR_SSL_CA => '/ca-cert.pem',
|
||||||
|
\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
21
tests/configs/mysql_ssl_ca_no_verify.php
Normal file
21
tests/configs/mysql_ssl_ca_no_verify.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$CONFIG = [
|
||||||
|
'overwrite.cli.url' => 'https://cloud.example.com',
|
||||||
|
'dbtype' => 'mysql',
|
||||||
|
'dbname' => 'nextcloud',
|
||||||
|
'dbhost' => 'db.example.com',
|
||||||
|
'dbport' => '',
|
||||||
|
'dbtableprefix' => 'oc_',
|
||||||
|
'dbuser' => 'nextcloud',
|
||||||
|
'dbpassword' => 'secret',
|
||||||
|
'redis' => [
|
||||||
|
'host' => 'localhost'
|
||||||
|
],
|
||||||
|
'dbdriveroptions' => [
|
||||||
|
\PDO::MYSQL_ATTR_SSL_KEY => '/ssl-key.pem',
|
||||||
|
\PDO::MYSQL_ATTR_SSL_CERT => '/ssl-cert.pem',
|
||||||
|
\PDO::MYSQL_ATTR_SSL_CA => '/ca-cert.pem',
|
||||||
|
\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
Loading…
Add table
Add a link
Reference in a new issue