forked from spacebar/account
parental controls
This commit is contained in:
parent
fa063d78fb
commit
124916e62c
6 changed files with 556 additions and 0 deletions
67
src/email.rs
67
src/email.rs
|
|
@ -70,3 +70,70 @@ pub async fn send_reset_email(to: &str, pwd: &str, username: &str) -> Result<(),
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_pc_email(to: &str, serial: &str) -> Result<(), String> {
|
||||
let smtp_user = env::var("SMTP_USER").map_err(|_| "SMTP_USER not set".to_string())?;
|
||||
let smtp_pass = env::var("SMTP_PASS").map_err(|_| "SMTP_PASS not set".to_string())?;
|
||||
let smtp_server = env::var("SMTP_SERVER").map_err(|_| "SMTP_SERVER not set".to_string())?;
|
||||
|
||||
// Load template
|
||||
let template = fs::read_to_string("res/email/parentalControlsTemplate.html")
|
||||
.map_err(|e| format!("Failed to read email template: {}", e))?;
|
||||
|
||||
// Replace placeholders
|
||||
let body = template
|
||||
.replace("{{serial}}", serial);
|
||||
|
||||
let email = Message::builder()
|
||||
.from(smtp_user.parse().unwrap())
|
||||
.to(to.parse().unwrap())
|
||||
.subject("Parental controls confirmation for SPFN")
|
||||
.header(lettre::message::header::ContentType::TEXT_HTML)
|
||||
.body(body)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let creds = Credentials::new(smtp_user, smtp_pass);
|
||||
|
||||
let mailer = SmtpTransport::relay(&smtp_server)
|
||||
.map_err(|e| e.to_string())?
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
mailer.send(&email).map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_reset_pin_email(to: &str, serial: &str, master_key: &str) -> Result<(), String> {
|
||||
let smtp_user = env::var("SMTP_USER").map_err(|_| "SMTP_USER not set".to_string())?;
|
||||
let smtp_pass = env::var("SMTP_PASS").map_err(|_| "SMTP_PASS not set".to_string())?;
|
||||
let smtp_server = env::var("SMTP_SERVER").map_err(|_| "SMTP_SERVER not set".to_string())?;
|
||||
|
||||
// Load template
|
||||
let template = fs::read_to_string("res/email/masterKeyTemplate.html")
|
||||
.map_err(|e| format!("Failed to read email template: {}", e))?;
|
||||
|
||||
// Replace placeholders
|
||||
let body = template
|
||||
.replace("{{serial}}", serial)
|
||||
.replace("{{mkey}}", master_key);
|
||||
|
||||
let email = Message::builder()
|
||||
.from(smtp_user.parse().unwrap())
|
||||
.to(to.parse().unwrap())
|
||||
.subject("Parental controls PIN reset for SPFN")
|
||||
.header(lettre::message::header::ContentType::TEXT_HTML)
|
||||
.body(body)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let creds = Credentials::new(smtp_user, smtp_pass);
|
||||
|
||||
let mailer = SmtpTransport::relay(&smtp_server)
|
||||
.map_err(|e| e.to_string())?
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
mailer.send(&email).map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -102,6 +102,8 @@ async fn launch() -> _ {
|
|||
nnid::support::verify_email,
|
||||
nnid::support::resend_email,
|
||||
nnid::support::forgotten_password,
|
||||
nnid::support::send_parental_controls_pin,
|
||||
nnid::support::send_forgotten_pin,
|
||||
nnid::people::create_account,
|
||||
nnid::people::get_own_profile,
|
||||
nnid::people::get_device_owner,
|
||||
|
|
|
|||
|
|
@ -220,5 +220,110 @@ pub async fn forgotten_password(
|
|||
UNAUTHORIZED_DEVICE_ERROR
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct DeviceSerial(pub String);
|
||||
|
||||
#[rocket::async_trait]
|
||||
impl<'r> FromRequest<'r> for DeviceSerial {
|
||||
type Error = Errors<'static>;
|
||||
|
||||
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
|
||||
match req.headers().get_one("x-nintendo-serial-number") {
|
||||
Some(val) if !val.trim().is_empty() => {
|
||||
request::Outcome::Success(DeviceSerial(val.to_string()))
|
||||
}
|
||||
_ => request::Outcome::Error((
|
||||
Status::BadRequest,
|
||||
Errors {
|
||||
error: &[Error {
|
||||
code: "0130",
|
||||
message: "Serial not found",
|
||||
}],
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/v1/api/support/send_confirmation/pin/<email>")]
|
||||
pub async fn send_parental_controls_pin(
|
||||
database: &State<Pool>,
|
||||
serial: DeviceSerial,
|
||||
email: &str,
|
||||
) -> Result<(), Errors<'static>> {
|
||||
let db = database.inner();
|
||||
let serial_number = serial.0;
|
||||
let email = email.trim().to_lowercase();
|
||||
|
||||
if email.is_empty() || !email.contains('@') {
|
||||
return Err(Errors {
|
||||
error: &[Error {
|
||||
code: "0103",
|
||||
message: "Email format is invalid",
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
let db_result = sqlx::query!(
|
||||
"
|
||||
INSERT INTO device_parental_controls (serial_number, email, updated_at)
|
||||
VALUES ($1, $2, NOW())
|
||||
ON CONFLICT (serial_number)
|
||||
DO UPDATE SET email = EXCLUDED.email, updated_at = NOW()
|
||||
",
|
||||
serial_number,
|
||||
email
|
||||
)
|
||||
.execute(db)
|
||||
.await;
|
||||
|
||||
if let Err(e) = db_result {
|
||||
eprintln!("Failed to associate serial {serial_number} with email {email}: {e}");
|
||||
return Err(Errors {
|
||||
error: &[Error {
|
||||
code: "0130",
|
||||
message: "PID has not been registered yet",
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
crate::email::send_pc_email(&email, &serial_number)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
eprintln!("Failed to send parental controls email to {email}: {e}");
|
||||
Errors {
|
||||
error: &[Error {
|
||||
code: "0130",
|
||||
message: "PID has not been registered yet",
|
||||
}],
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[get("/v1/api/support/send_forgotten/pin/<email>/<master_key>")]
|
||||
pub async fn send_forgotten_pin(
|
||||
serial: DeviceSerial,
|
||||
email: &str,
|
||||
master_key: &str,
|
||||
) -> Result<(), Errors<'static>> {
|
||||
let serial_number = serial.0;
|
||||
let email = email.trim().to_lowercase();
|
||||
|
||||
crate::email::send_reset_pin_email(&email, &serial_number, &master_key)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
eprintln!("Failed to send parental controls email to {email}: {e}");
|
||||
Errors {
|
||||
error: &[Error {
|
||||
code: "0130",
|
||||
message: "PID has not been registered yet",
|
||||
}],
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Reference in a new issue