awa
This commit is contained in:
@@ -11,7 +11,7 @@ jsonwebtoken = "9.2"
|
||||
bcrypt = "0.15"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
colored = "2.1.0"
|
||||
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres", "chrono", "uuid", "migrate", "json"] }
|
||||
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "mysql", "chrono", "uuid", "migrate", "json"] }
|
||||
anyhow = "1.0.86"
|
||||
futures = "0.3.30"
|
||||
macros-rs = "1.2.1"
|
||||
|
||||
@@ -5,7 +5,7 @@ address = "127.0.0.1"
|
||||
port = 8085
|
||||
|
||||
[server.database]
|
||||
url = "postgresql://username:password@localhost:5432/domains"
|
||||
url = "mysql://root:password@localhost:3306/dns"
|
||||
|
||||
# Maximum number of database connections
|
||||
max_connections = 10
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
registrations_remaining INTEGER DEFAULT 3,
|
||||
@@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS invite_codes (
|
||||
code VARCHAR(32) UNIQUE NOT NULL,
|
||||
created_by INTEGER REFERENCES users(id),
|
||||
used_by INTEGER REFERENCES users(id),
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
used_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
@@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS dns_records (
|
||||
value VARCHAR(1000) NOT NULL,
|
||||
ttl INTEGER DEFAULT 3600,
|
||||
priority INTEGER, -- For MX records
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_dns_records_domain_type ON dns_records(domain_id, record_type);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-- Make IP column optional for domains
|
||||
ALTER TABLE domains ALTER COLUMN ip DROP NOT NULL;
|
||||
ALTER TABLE domains MODIFY COLUMN ip VARCHAR(255) NULL;
|
||||
|
||||
-- Update DNS records constraint to only allow A, AAAA, CNAME, TXT
|
||||
ALTER TABLE dns_records DROP CONSTRAINT IF EXISTS dns_records_record_type_check;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
-- Re-add NS record support and extend record types
|
||||
ALTER TABLE dns_records DROP CONSTRAINT IF EXISTS dns_records_record_type_check;
|
||||
ALTER TABLE dns_records DROP CONSTRAINT dns_records_record_type_check;
|
||||
ALTER TABLE dns_records ADD CONSTRAINT dns_records_record_type_check
|
||||
CHECK (record_type IN ('A', 'AAAA', 'CNAME', 'TXT', 'NS', 'MX'));
|
||||
|
||||
-- Add index for efficient NS record lookups during delegation
|
||||
CREATE INDEX IF NOT EXISTS idx_dns_records_ns_lookup ON dns_records(record_type, name) WHERE record_type = 'NS';
|
||||
CREATE INDEX idx_dns_records_ns_lookup ON dns_records(record_type, name) WHERE record_type = 'NS';
|
||||
|
||||
-- Add index for subdomain resolution optimization
|
||||
CREATE INDEX IF NOT EXISTS idx_dns_records_subdomain_lookup ON dns_records(domain_id, name, record_type);
|
||||
CREATE INDEX idx_dns_records_subdomain_lookup ON dns_records(domain_id, name, record_type);
|
||||
@@ -4,5 +4,5 @@ ALTER TABLE dns_records ADD CONSTRAINT dns_records_record_type_check
|
||||
CHECK (record_type IN ('A', 'AAAA', 'CNAME', 'TXT', 'NS'));
|
||||
|
||||
-- Add indexes for efficient DNS lookups if they don't exist
|
||||
CREATE INDEX IF NOT EXISTS idx_dns_records_ns_lookup ON dns_records(record_type, name) WHERE record_type = 'NS';
|
||||
CREATE INDEX IF NOT EXISTS idx_dns_records_subdomain_lookup ON dns_records(domain_id, name, record_type);
|
||||
CREATE INDEX idx_dns_records_ns_lookup ON dns_records(record_type, name);
|
||||
CREATE INDEX idx_dns_records_subdomain_lookup ON dns_records(domain_id, name, record_type);
|
||||
@@ -1,18 +1,18 @@
|
||||
-- Add certificate challenges table for CA functionality
|
||||
CREATE TABLE IF NOT EXISTS certificate_challenges (
|
||||
id SERIAL PRIMARY KEY,
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
token VARCHAR(255) UNIQUE NOT NULL,
|
||||
domain VARCHAR(255) NOT NULL,
|
||||
challenge_type VARCHAR(20) NOT NULL CHECK (challenge_type IN ('dns')),
|
||||
challenge_type VARCHAR(20) NOT NULL,
|
||||
verification_data VARCHAR(500) NOT NULL,
|
||||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'valid', 'invalid', 'expired')),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
status VARCHAR(20) DEFAULT 'pending',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMPTZ NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_certificate_challenges_token ON certificate_challenges(token);
|
||||
CREATE INDEX IF NOT EXISTS idx_certificate_challenges_domain ON certificate_challenges(domain);
|
||||
CREATE INDEX IF NOT EXISTS idx_certificate_challenges_expires_at ON certificate_challenges(expires_at);
|
||||
CREATE INDEX idx_certificate_challenges_token ON certificate_challenges(token);
|
||||
CREATE INDEX idx_certificate_challenges_domain ON certificate_challenges(domain);
|
||||
CREATE INDEX idx_certificate_challenges_expires_at ON certificate_challenges(expires_at);
|
||||
|
||||
-- Add table to store issued certificates
|
||||
CREATE TABLE IF NOT EXISTS issued_certificates (
|
||||
@@ -21,13 +21,13 @@ CREATE TABLE IF NOT EXISTS issued_certificates (
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
certificate_pem TEXT NOT NULL,
|
||||
private_key_pem TEXT NOT NULL,
|
||||
issued_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
revoked_at TIMESTAMPTZ,
|
||||
serial_number VARCHAR(255) UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_issued_certificates_domain ON issued_certificates(domain);
|
||||
CREATE INDEX IF NOT EXISTS idx_issued_certificates_user_id ON issued_certificates(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_issued_certificates_serial ON issued_certificates(serial_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_issued_certificates_expires_at ON issued_certificates(expires_at);
|
||||
CREATE INDEX idx_issued_certificates_domain ON issued_certificates(domain);
|
||||
CREATE INDEX idx_issued_certificates_user_id ON issued_certificates(user_id);
|
||||
CREATE INDEX idx_issued_certificates_serial ON issued_certificates(serial_number);
|
||||
CREATE INDEX idx_issued_certificates_expires_at ON issued_certificates(expires_at);
|
||||
@@ -2,6 +2,26 @@
|
||||
DELETE FROM dns_records WHERE record_type NOT IN ('A', 'AAAA', 'CNAME', 'TXT');
|
||||
|
||||
-- Now apply the constraint
|
||||
ALTER TABLE dns_records DROP CONSTRAINT IF EXISTS dns_records_record_type_check;
|
||||
ALTER TABLE dns_records ADD CONSTRAINT dns_records_record_type_check
|
||||
CHECK (record_type IN ('A', 'AAAA', 'CNAME', 'TXT'));
|
||||
ALTER TABLE dns_records DROP CONSTRAINT dns_records_record_type_check;
|
||||
|
||||
-- MySQL doesn't support table-level CHECK constraints, using trigger instead
|
||||
DELIMITER //
|
||||
CREATE TRIGGER check_record_type_before_insert
|
||||
BEFORE INSERT ON dns_records
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.record_type NOT IN ('A', 'AAAA', 'CNAME', 'TXT') THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Invalid record type';
|
||||
END IF;
|
||||
END;
|
||||
//
|
||||
CREATE TRIGGER check_record_type_before_update
|
||||
BEFORE UPDATE ON dns_records
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.record_type NOT IN ('A', 'AAAA', 'CNAME', 'TXT') THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Invalid record type';
|
||||
END IF;
|
||||
END;
|
||||
//
|
||||
DELIMITER ;
|
||||
@@ -1,8 +1,8 @@
|
||||
-- Add table to store CA certificate and key
|
||||
CREATE TABLE IF NOT EXISTS ca_certificates (
|
||||
id SERIAL PRIMARY KEY,
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ca_cert_pem TEXT NOT NULL,
|
||||
ca_key_pem TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
is_active BOOLEAN DEFAULT TRUE
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active TINYINT(1) DEFAULT 1
|
||||
);
|
||||
@@ -1,2 +1,2 @@
|
||||
-- Add CSR field to certificate challenges
|
||||
ALTER TABLE certificate_challenges ADD COLUMN IF NOT EXISTS csr_pem TEXT;
|
||||
ALTER TABLE certificate_challenges ADD COLUMN csr_pem TEXT;
|
||||
@@ -1,28 +1,25 @@
|
||||
-- Search engine domain crawl status tracking
|
||||
CREATE TABLE IF NOT EXISTS domain_crawl_status (
|
||||
domain_id INTEGER PRIMARY KEY REFERENCES domains(id) ON DELETE CASCADE,
|
||||
last_crawled_at TIMESTAMPTZ,
|
||||
next_crawl_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
domain_id INT PRIMARY KEY, FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE,
|
||||
last_crawled_at TIMESTAMP,
|
||||
next_crawl_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
crawl_status VARCHAR(20) DEFAULT 'pending' CHECK (crawl_status IN ('pending', 'crawling', 'completed', 'failed', 'disabled')),
|
||||
error_message TEXT,
|
||||
pages_found INTEGER DEFAULT 0,
|
||||
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_domain_crawl_status_next_crawl ON domain_crawl_status(next_crawl_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_domain_crawl_status_status ON domain_crawl_status(crawl_status);
|
||||
|
||||
-- Function to update the updated_at column
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger for updated_at
|
||||
DROP TRIGGER IF EXISTS update_domain_crawl_status_updated_at ON domain_crawl_status;
|
||||
-- MySQL trigger to update updated_at column
|
||||
DELIMITER //
|
||||
CREATE TRIGGER update_domain_crawl_status_updated_at
|
||||
BEFORE UPDATE ON domain_crawl_status
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SET NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
END;
|
||||
//
|
||||
DELIMITER ;
|
||||
@@ -3,7 +3,7 @@ mod structs;
|
||||
|
||||
use colored::Colorize;
|
||||
use macros_rs::fmt::{crashln, string};
|
||||
use sqlx::{PgPool, Error};
|
||||
use sqlx::{MySqlPool, Error};
|
||||
use std::fs::write;
|
||||
use structs::{Auth, Database, Server, Settings};
|
||||
|
||||
@@ -22,7 +22,7 @@ impl Config {
|
||||
address: "127.0.0.1".into(),
|
||||
port: 8080,
|
||||
database: Database {
|
||||
url: "postgresql://username:password@localhost/domains".into(),
|
||||
url: "mysql://root:password@localhost:3306/dns".into(),
|
||||
max_connections: 10,
|
||||
},
|
||||
cert_path: "localhost+2.pem".into(),
|
||||
@@ -64,13 +64,13 @@ impl Config {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub async fn connect_to_db(&self) -> Result<PgPool, Error> {
|
||||
let pool = PgPool::connect(&self.server.database.url).await?;
|
||||
pub async fn connect_to_db(&self) -> Result<MySqlPool, Error> {
|
||||
let pool = MySqlPool::connect(&self.server.database.url).await?;
|
||||
|
||||
// Run migrations
|
||||
sqlx::migrate!("./migrations").run(&pool).await?;
|
||||
|
||||
log::info!("PostgreSQL database connected");
|
||||
log::info!("MySQL database connected");
|
||||
Ok(pool)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,8 +200,10 @@ pub(crate) async fn create_invite(_ctx: &ServerContext, app_state: AppState, cla
|
||||
let mut tx = app_state.db.begin().await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
let affected_rows = sqlx::query("UPDATE users SET registrations_remaining = registrations_remaining - 1 WHERE id = $1 AND registrations_remaining > 0")
|
||||
.bind(claims.user_id)
|
||||
let affected_rows = sqlx::query(
|
||||
"UPDATE users SET registrations_remaining = registrations_remaining - 1 WHERE id = ? AND registrations_remaining > 0"
|
||||
)
|
||||
.bind(claims.user_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?
|
||||
@@ -214,7 +216,7 @@ pub(crate) async fn create_invite(_ctx: &ServerContext, app_state: AppState, cla
|
||||
})?);
|
||||
}
|
||||
|
||||
sqlx::query("INSERT INTO invite_codes (code, created_by, created_at) VALUES ($1, $2, $3)")
|
||||
sqlx::query("INSERT INTO invite_codes (code, created_by, created_at) VALUES (?, ?, ?)")
|
||||
.bind(&invite_code)
|
||||
.bind(claims.user_id)
|
||||
.bind(Utc::now())
|
||||
@@ -259,16 +261,16 @@ pub(crate) async fn redeem_invite(ctx: &ServerContext, app_state: AppState, clai
|
||||
let mut tx = app_state.db.begin().await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
sqlx::query("UPDATE invite_codes SET used_by = $1, used_at = $2 WHERE id = $3")
|
||||
.bind(claims.user_id)
|
||||
.bind(Utc::now())
|
||||
.bind(invite.id)
|
||||
sqlx::query("UPDATE invite_codes SET used_by = ?, used_at = ? WHERE id = ?")
|
||||
.bind(claims.user_id)
|
||||
.bind(Utc::now())
|
||||
.bind(invite.id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
sqlx::query("UPDATE users SET registrations_remaining = registrations_remaining + 1 WHERE id = $1")
|
||||
.bind(claims.user_id)
|
||||
sqlx::query("UPDATE users SET registrations_remaining = registrations_remaining + 1 WHERE id = ?")
|
||||
.bind(claims.user_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
@@ -313,8 +315,10 @@ pub(crate) async fn create_domain_invite(_ctx: &ServerContext, app_state: AppSta
|
||||
let mut tx = app_state.db.begin().await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
let affected_rows = sqlx::query("UPDATE users SET domain_invite_codes = domain_invite_codes - 1 WHERE id = $1 AND domain_invite_codes > 0")
|
||||
.bind(claims.user_id)
|
||||
let affected_rows = sqlx::query(
|
||||
"UPDATE users SET domain_invite_codes = domain_invite_codes - 1 WHERE id = ? AND domain_invite_codes > 0"
|
||||
)
|
||||
.bind(claims.user_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?
|
||||
@@ -367,16 +371,16 @@ pub(crate) async fn redeem_domain_invite(ctx: &ServerContext, app_state: AppStat
|
||||
let mut tx = app_state.db.begin().await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
sqlx::query("UPDATE domain_invite_codes SET used_by = $1, used_at = $2 WHERE id = $3")
|
||||
.bind(claims.user_id)
|
||||
.bind(Utc::now())
|
||||
.bind(invite.id)
|
||||
sqlx::query("UPDATE domain_invite_codes SET used_by = ?, used_at = ? WHERE id = ?")
|
||||
.bind(claims.user_id)
|
||||
.bind(Utc::now())
|
||||
.bind(invite.id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
sqlx::query("UPDATE users SET domain_invite_codes = domain_invite_codes + 1 WHERE id = $1")
|
||||
.bind(claims.user_id)
|
||||
sqlx::query("UPDATE users SET domain_invite_codes = domain_invite_codes + 1 WHERE id = ?")
|
||||
.bind(claims.user_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
|
||||
@@ -78,9 +78,9 @@ pub(crate) async fn create_logic(domain: Domain, user_id: i32, app: &AppState) -
|
||||
}
|
||||
|
||||
let existing_count: i64 =
|
||||
sqlx::query_scalar("SELECT COUNT(*) FROM domains WHERE name = $1 AND tld = $2")
|
||||
.bind(&domain.name)
|
||||
.bind(&domain.tld)
|
||||
sqlx::query_scalar("SELECT COUNT(*) FROM domains WHERE name = ? AND tld = ?")
|
||||
.bind(&domain.name)
|
||||
.bind(&domain.tld)
|
||||
.fetch_one(&app.db)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database error"))?;
|
||||
@@ -89,7 +89,7 @@ pub(crate) async fn create_logic(domain: Domain, user_id: i32, app: &AppState) -
|
||||
return Err(GurtError::invalid_message("Domain already exists"));
|
||||
}
|
||||
|
||||
let user: (String,) = sqlx::query_as("SELECT username FROM users WHERE id = $1")
|
||||
let user: (String,) = sqlx::query_as("SELECT username FROM users WHERE id = ?")
|
||||
.bind(user_id)
|
||||
.fetch_one(&app.db)
|
||||
.await
|
||||
@@ -98,7 +98,7 @@ pub(crate) async fn create_logic(domain: Domain, user_id: i32, app: &AppState) -
|
||||
let username = user.0;
|
||||
|
||||
let domain_row: (i32,) = sqlx::query_as(
|
||||
"INSERT INTO domains (name, tld, user_id, status) VALUES ($1, $2, $3, 'pending') RETURNING id"
|
||||
"INSERT INTO domains (name, tld, user_id, status) VALUES (?, ?, ?, 'pending') RETURNING id"
|
||||
)
|
||||
.bind(&domain.name)
|
||||
.bind(&domain.tld)
|
||||
@@ -110,7 +110,7 @@ pub(crate) async fn create_logic(domain: Domain, user_id: i32, app: &AppState) -
|
||||
let domain_id = domain_row.0;
|
||||
|
||||
let affected_rows = sqlx::query(
|
||||
"UPDATE users SET registrations_remaining = registrations_remaining - 1 WHERE id = $1 AND registrations_remaining > 0",
|
||||
"UPDATE users SET registrations_remaining = registrations_remaining - 1 WHERE id = ? AND registrations_remaining > 0",
|
||||
)
|
||||
.bind(user_id)
|
||||
.execute(&app.db)
|
||||
@@ -119,8 +119,8 @@ pub(crate) async fn create_logic(domain: Domain, user_id: i32, app: &AppState) -
|
||||
.rows_affected();
|
||||
|
||||
if affected_rows == 0 {
|
||||
sqlx::query("DELETE FROM domains WHERE id = $1")
|
||||
.bind(domain_id)
|
||||
sqlx::query("DELETE FROM domains WHERE id = ?")
|
||||
.bind(domain_id)
|
||||
.execute(&app.db)
|
||||
.await
|
||||
.map_err(|_| GurtError::invalid_message("Database cleanup error"))?;
|
||||
@@ -321,7 +321,7 @@ pub(crate) async fn delete_domain(
|
||||
return Ok(GurtResponse::not_found().with_string_body("Domain not found or access denied"));
|
||||
}
|
||||
|
||||
sqlx::query("DELETE FROM domains WHERE name = $1 AND tld = $2 AND user_id = $3")
|
||||
sqlx::query("DELETE FROM domains WHERE name = ? AND tld = ? AND user_id = ?")
|
||||
.bind(name)
|
||||
.bind(tld)
|
||||
.bind(claims.user_id)
|
||||
@@ -620,7 +620,7 @@ pub(crate) async fn delete_domain_record(
|
||||
}
|
||||
};
|
||||
|
||||
let rows_affected = sqlx::query("DELETE FROM dns_records WHERE id = $1 AND domain_id = $2")
|
||||
let rows_affected = sqlx::query("DELETE FROM dns_records WHERE id = ? AND domain_id = ?")
|
||||
.bind(record_id)
|
||||
.bind(domain.id.unwrap())
|
||||
.execute(&app_state.db)
|
||||
@@ -1066,7 +1066,7 @@ pub(crate) async fn get_certificate(
|
||||
});
|
||||
|
||||
// Delete the challenge as it's completed
|
||||
sqlx::query("DELETE FROM certificate_challenges WHERE token = $1")
|
||||
sqlx::query("DELETE FROM certificate_challenges WHERE token = ?")
|
||||
.bind(token)
|
||||
.execute(&app_state.db)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user