This commit is contained in:
GABRIELNGBTUC 2025-01-26 13:21:50 +00:00 committed by GitHub
commit 8a1b8cb16b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 85 additions and 2 deletions

View file

@ -184,10 +184,18 @@ class Database {
/**
* @typedef {string|undefined} envString
* @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} dbConfig the database configuration that should be written
* @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString, caFilePath:envString}} dbConfig the database configuration that should be written
* @returns {void}
*/
static writeDBConfig(dbConfig) {
// Move CA file to the data directory
if (dbConfig.caFilePath) {
const dataCaFilePath = path.join(Database.dataDir, "mariadb-ca.pem");
fs.renameSync(dbConfig.caFilePath, dataCaFilePath);
dbConfig.caFilePath = dataCaFilePath;
dbConfig.ssl = undefined;
dbConfig.caFile = undefined;
}
fs.writeFileSync(path.join(Database.dataDir, "db-config.json"), JSON.stringify(dbConfig, null, 4));
}
@ -259,11 +267,22 @@ class Database {
throw Error("Invalid database name. A database name can only consist of letters, numbers and underscores");
}
let sslConfig = null;
let serverCa = undefined;
if (dbConfig.caFilePath) {
serverCa = [ fs.readFileSync(dbConfig.caFilePath, "utf8") ];
sslConfig = {
rejectUnauthorized: true,
ca: serverCa
};
}
const connection = await mysql.createConnection({
host: dbConfig.hostname,
port: dbConfig.port,
user: dbConfig.username,
password: dbConfig.password,
ssl: sslConfig
});
await connection.execute("CREATE DATABASE IF NOT EXISTS " + dbConfig.dbName + " CHARACTER SET utf8mb4");
@ -277,7 +296,9 @@ class Database {
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.dbName,
ssl: sslConfig,
timezone: "Z",
//ssl: sslConfig,
typeCast: function (field, next) {
if (field.type === "DATETIME") {
// Do not perform timezone conversion

View file

@ -77,6 +77,7 @@ class SetupDatabase {
dbConfig.dbName = process.env.UPTIME_KUMA_DB_NAME;
dbConfig.username = process.env.UPTIME_KUMA_DB_USERNAME;
dbConfig.password = process.env.UPTIME_KUMA_DB_PASSWORD;
dbConfig.caFilePath = process.env.UPTIME_KUMA_DB_CA_CERT;
Database.writeDBConfig(dbConfig);
}
@ -206,13 +207,43 @@ class SetupDatabase {
return;
}
// Prevent someone from injecting a CA file path not generated by the code below
if (dbConfig.caFilePath) {
dbConfig.caFilePath = undefined;
}
if (dbConfig.caFile) {
const base64Data = dbConfig.caFile.replace(/^data:application\/octet-stream;base64,/, "");
const binaryData = Buffer.from(base64Data, "base64").toString("binary");
const tempCaDirectory = fs.mkdtempSync("kuma-ca-");
dbConfig.caFilePath = path.join(tempCaDirectory, "ca.pem");
try {
fs.writeFileSync(dbConfig.caFilePath, binaryData, "binary");
} catch (err) {
response.status(400).json("Cannot write CA file: " + err.message);
this.runningSetup = false;
return;
}
dbConfig.ssl = {
rejectUnauthorized: true,
ca: [ fs.readFileSync(dbConfig.caFilePath) ]
};
}
// Test connection
try {
let sslConfig = null;
if (dbConfig.ssl) {
sslConfig = dbConfig.ssl;
}
const connection = await mysql.createConnection({
host: dbConfig.hostname,
port: dbConfig.port,
user: dbConfig.username,
password: dbConfig.password,
ssl: sslConfig
});
await connection.execute("SELECT 1");
connection.end();

View file

@ -4,6 +4,7 @@
"setupDatabaseEmbeddedMariaDB": "You don't need to set anything. This docker image has embedded and configured MariaDB for you automatically. Uptime Kuma will connect to this database via unix socket.",
"setupDatabaseMariaDB": "Connect to an external MariaDB database. You need to set the database connection information.",
"setupDatabaseSQLite": "A simple database file, recommended for small-scale deployments. Prior to v2.0.0, Uptime Kuma used SQLite as the default database.",
"configureMariaCaFile": "You will sometimes need to provide a CA certificate to connect to database with 'require-secure-transport' on. Such as when using Azure MySql flexible servers. You can upload the CA file that will be used to enable a secure connection.",
"settingUpDatabaseMSG": "Setting up the database. It may take a while, please be patient.",
"dbName": "Database Name",
"Settings": "Settings",

View file

@ -90,8 +90,12 @@
<input id="floatingInput" v-model="dbConfig.dbName" type="text" class="form-control" required>
<label for="floatingInput">{{ $t("dbName") }}</label>
</div>
</template>
<div class="mb2 mt-3 short">
<p class="mb-2">{{ $t("configureMariaCaFile") }}</p>
<input id="ca-input" type="file" accept="application/x-pem-file, .pem" class="form-control" @change="onCaFileChange">
</div>
</template>
<button class="btn btn-primary mt-4 short" type="submit" :disabled="disabledButton">
{{ $t("Next") }}
</button>
@ -117,6 +121,7 @@ export default {
username: "",
password: "",
dbName: "kuma",
caFile: ""
},
info: {
needSetup: false,
@ -178,6 +183,15 @@ export default {
}
},
onCaFileChange(e) {
const fileReader = new FileReader();
fileReader.onload = () => {
this.dbConfig.caFile = fileReader.result;
console.log(this.dbConfig.caFile);
};
fileReader.readAsDataURL(e.target.files[0]);
},
test() {
this.$root.toastError("not implemented");
}
@ -186,6 +200,22 @@ export default {
</script>
<style lang="scss" scoped>
@import "../assets/vars.scss";
.dark {
#ca-input {
&::file-selector-button {
color: $primary;
background-color: $dark-bg;
}
&:hover:not(:disabled):not([readonly])::file-selector-button {
color: $dark-font-color2;
background-color: $primary;
}
}
}
.form-container {
display: flex;
align-items: center;