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]
|
||||
name = "nextcloud-config-parser"
|
||||
description = "Rust parser for nextcloud config files"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
|
|
|||
35
src/lib.rs
35
src/lib.rs
|
|
@ -127,6 +127,18 @@ pub enum NotAConfigError {
|
|||
NotAnArray(PathBuf),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SslOptions {
|
||||
Enabled {
|
||||
key: String,
|
||||
cert: String,
|
||||
ca: String,
|
||||
verify: bool,
|
||||
},
|
||||
Disabled,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Database {
|
||||
Sqlite {
|
||||
|
|
@ -137,14 +149,14 @@ pub enum Database {
|
|||
username: String,
|
||||
password: String,
|
||||
connect: DbConnect,
|
||||
disable_ssl: bool,
|
||||
ssl_options: SslOptions,
|
||||
},
|
||||
Postgres {
|
||||
database: String,
|
||||
username: String,
|
||||
password: String,
|
||||
connect: DbConnect,
|
||||
disable_ssl: bool,
|
||||
ssl_options: SslOptions,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -172,15 +184,26 @@ impl From<Database> for sqlx::any::AnyConnectOptions {
|
|||
username,
|
||||
password,
|
||||
connect,
|
||||
disable_ssl,
|
||||
ssl_options,
|
||||
} => {
|
||||
let mut options = MySqlConnectOptions::default()
|
||||
.database(&database)
|
||||
.username(&username)
|
||||
.password(&password);
|
||||
if disable_ssl {
|
||||
match ssl_options {
|
||||
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 {
|
||||
DbConnect::Socket(socket) => {
|
||||
options = options.socket(socket);
|
||||
|
|
@ -196,13 +219,13 @@ impl From<Database> for sqlx::any::AnyConnectOptions {
|
|||
username,
|
||||
password,
|
||||
connect,
|
||||
disable_ssl,
|
||||
ssl_options,
|
||||
} => {
|
||||
let mut options = PgConnectOptions::default()
|
||||
.database(&database)
|
||||
.username(&username)
|
||||
.password(&password);
|
||||
if disable_ssl {
|
||||
if matches!(ssl_options, SslOptions::Disabled) {
|
||||
options = options.ssl_mode(PgSslMode::Disable);
|
||||
}
|
||||
match connect {
|
||||
|
|
|
|||
147
src/nc.rs
147
src/nc.rs
|
|
@ -1,6 +1,8 @@
|
|||
#[cfg(feature = "redis-connect")]
|
||||
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;
|
||||
#[cfg(feature = "redis-connect")]
|
||||
use redis::{ConnectionAddr, ConnectionInfo, RedisConnectionInfo};
|
||||
|
|
@ -16,6 +18,10 @@ static CONFIG_CONSTANTS: &[(&str, &str)] = &[
|
|||
(r"\RedisCluster::FAILOVER_ERROR", "1"),
|
||||
(r"\RedisCluster::DISTRIBUTE", "2"),
|
||||
(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> {
|
||||
|
|
@ -174,12 +180,35 @@ fn parse_db_options(parsed: &Value) -> Result<Database> {
|
|||
}
|
||||
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 {
|
||||
database: database.into(),
|
||||
username: username.into(),
|
||||
password: password.into(),
|
||||
connect,
|
||||
disable_ssl,
|
||||
ssl_options,
|
||||
})
|
||||
}
|
||||
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 ssl_options = if disable_ssl {
|
||||
SslOptions::Disabled
|
||||
} else {
|
||||
SslOptions::Default
|
||||
};
|
||||
|
||||
Ok(Database::Postgres {
|
||||
database: database.into(),
|
||||
username: username.into(),
|
||||
password: password.into(),
|
||||
connect,
|
||||
disable_ssl,
|
||||
ssl_options,
|
||||
})
|
||||
}
|
||||
Some("sqlite3") => {
|
||||
|
|
@ -375,7 +410,7 @@ fn test_parse_config_basic() {
|
|||
host: "127.0.0.1".to_string(),
|
||||
port: 3306,
|
||||
},
|
||||
disable_ssl: true,
|
||||
ssl_options: SslOptions::Disabled,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -444,7 +479,7 @@ fn test_parse_comment_whitespace() {
|
|||
host: "127.0.0.1".to_string(),
|
||||
port: 3306,
|
||||
},
|
||||
disable_ssl: true,
|
||||
ssl_options: SslOptions::Disabled,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -475,7 +510,7 @@ fn test_parse_port_in_host() {
|
|||
host: "127.0.0.1".to_string(),
|
||||
port: 1234,
|
||||
},
|
||||
disable_ssl: true,
|
||||
ssl_options: SslOptions::Disabled,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -498,7 +533,7 @@ fn test_parse_postgres_socket() {
|
|||
username: "redacted".to_string(),
|
||||
password: "redacted".to_string(),
|
||||
connect: DbConnect::Socket("/var/run/postgresql".into()),
|
||||
disable_ssl: false,
|
||||
ssl_options: SslOptions::Default,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -524,7 +559,7 @@ fn test_parse_postgres_socket_folder() {
|
|||
username: "redacted".to_string(),
|
||||
password: "redacted".to_string(),
|
||||
connect: DbConnect::Socket("/var/run/postgresql".into()),
|
||||
disable_ssl: false,
|
||||
ssl_options: SslOptions::Default,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -574,7 +609,7 @@ fn test_parse_config_multiple() {
|
|||
host: "127.0.0.1".to_string(),
|
||||
port: 3306,
|
||||
},
|
||||
disable_ssl: true,
|
||||
ssl_options: SslOptions::Disabled,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -628,7 +663,7 @@ fn test_parse_config_mysql_fqdn() {
|
|||
host: "db.example.com".to_string(),
|
||||
port: 3306,
|
||||
},
|
||||
disable_ssl: false,
|
||||
ssl_options: SslOptions::Default,
|
||||
},
|
||||
&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]
|
||||
fn test_parse_postgres_ip() {
|
||||
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(),
|
||||
port: 5432,
|
||||
},
|
||||
disable_ssl: true,
|
||||
ssl_options: SslOptions::Disabled,
|
||||
},
|
||||
&config.database,
|
||||
);
|
||||
|
|
@ -684,7 +807,7 @@ fn test_parse_postgres_fqdn() {
|
|||
host: "pg.example.com".to_string(),
|
||||
port: 5432,
|
||||
},
|
||||
disable_ssl: false,
|
||||
ssl_options: SslOptions::Default,
|
||||
},
|
||||
&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