Skip to content

Commit

Permalink
Merge pull request #2 from sebadob/browser-language-detector
Browse files Browse the repository at this point in the history
browser native language detection
  • Loading branch information
sebadob committed Jul 26, 2023
2 parents 60a499a + dae0135 commit 884f599
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 1 deletion.
1 change: 1 addition & 0 deletions rauthy-common/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub const APPLICATION_JSON: &str = "application/json";
pub const TOKEN_BEARER: &str = "Bearer";
pub const COOKIE_SESSION: &str = "rauthy-session";
pub const COOKIE_MFA: &str = "rauthy-mfa";
pub const COOKIE_LOCALE: &str = "locale";
pub const PWD_RESET_COOKIE: &str = "rauthy-pwd-reset";
pub const APP_ID_HEADER: &str = "mfa-app-id";
pub const CSRF_HEADER: &str = "csrf-token";
Expand Down
10 changes: 9 additions & 1 deletion rauthy-handlers/src/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rauthy_models::entity::password::{PasswordHashTimes, PasswordPolicy};
use rauthy_models::entity::pow::Pow;
use rauthy_models::entity::principal::Principal;
use rauthy_models::entity::sessions::Session;
use rauthy_models::language::Language;
use rauthy_models::request::{
EncKeyMigrateRequest, PasswordHashTimesRequest, PasswordPolicyRequest,
};
Expand Down Expand Up @@ -69,10 +70,17 @@ pub async fn get_static_assets(

#[get("/account")]
#[has_permissions("all")]
pub async fn get_account_html(data: web::Data<AppState>) -> Result<HttpResponse, ErrorResponse> {
pub async fn get_account_html(
data: web::Data<AppState>,
req: HttpRequest,
) -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy(&data).await?;
let (body, nonce) = AccountHtml::build(&colors);

// TODO use for testing i18n
let lang = Language::try_from(&req).unwrap_or_default();
tracing::info!("lang: {:?}", lang);

Ok(HttpResponse::Ok()
.insert_header(HEADER_HTML)
.insert_header(build_csp_header(&nonce))
Expand Down
5 changes: 5 additions & 0 deletions rauthy-handlers/src/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rauthy_models::entity::principal::Principal;
use rauthy_models::entity::sessions::{Session, SessionState};
use rauthy_models::entity::users::User;
use rauthy_models::entity::webauthn::WebauthnCookie;
use rauthy_models::language::Language;
use rauthy_models::request::{
AuthRequest, LoginRefreshRequest, LoginRequest, LogoutRequest, RefreshTokenRequest,
TokenRequest, TokenValidationRequest,
Expand Down Expand Up @@ -55,6 +56,10 @@ pub async fn get_authorize(
)
.await?;

// TODO use for testing i18n
let lang = Language::try_from(&req).unwrap_or_default();
tracing::info!("lang: {:?}", lang);

let colors = ColorEntity::find(&data, &req_data.client_id).await?;

if session.is_some() && session.as_ref().unwrap().state == SessionState::Auth {
Expand Down
1 change: 1 addition & 0 deletions rauthy-models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ authors = ["Sebastian Dobe <sebastiandobe@mailbox.org>"]
license = "AGPLv3"

[dependencies]
accept-language = "3"
actix = "0.13"
actix-multipart = "0.6"
actix-web = { version = "4", features = ["rustls"] }
Expand Down
86 changes: 86 additions & 0 deletions rauthy-models/src/language.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use actix_web::http::header::{HeaderValue, ACCEPT_LANGUAGE};
use actix_web::HttpRequest;
use rauthy_common::constants::COOKIE_LOCALE;
use rauthy_common::error_response::{ErrorResponse, ErrorResponseType};
use serde::{Deserialize, Serialize};
use tracing::debug;

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum Language {
En,
De,
}

impl Language {
fn all_available<'a>() -> [&'a str; 4] {
["en", "en-US", "de", "de-DE"]
}

pub fn as_str(&self) -> &str {
match self {
Language::En => "en",
Language::De => "de",
}
}

// pub fn set_cookie_str(&self) -> (&'static str, HeaderValue) {
// (
// "Set-Cookie",
// HeaderValue::from_str(&format!(
// "{}={};Path=/;Max-Age={};SameSite=Lax",
// // "{}={};Path=/;Max-Age={};SameSite=Lax;Secure=true",
// LOCALE_COOKIE,
// self.as_str(),
// 15552000
// ))
// .unwrap(),
// )
// }
}

impl Default for Language {
fn default() -> Self {
Self::En
}
}

impl From<&HeaderValue> for Language {
fn from(value: &HeaderValue) -> Self {
Language::from(value.to_str().unwrap_or_default())
}
}

impl From<&str> for Language {
fn from(value: &str) -> Self {
match value {
"de" | "de-DE" => Self::De,
"en" | "en-US" => Self::En,
_ => Self::default(),
}
}
}

impl TryFrom<&HttpRequest> for Language {
type Error = ErrorResponse;

fn try_from(value: &HttpRequest) -> Result<Self, Self::Error> {
if let Some(cookie) = value.headers().get(COOKIE_LOCALE) {
return Ok(Language::from(cookie));
}

if let Some(accept_lang) = value.headers().get(ACCEPT_LANGUAGE) {
let accept_as_str = accept_lang.to_str().unwrap_or_default();
let common_languages =
accept_language::intersection(accept_as_str, &Language::all_available());
debug!("common_languages: {:?}", common_languages);
if !common_languages.is_empty() {
return Ok(Language::from(common_languages.get(0).unwrap().as_str()));
}
}

Err(ErrorResponse::new(
ErrorResponseType::NotFound,
"Could not find and extract a locale cookie or the accept-language header".to_string(),
))
}
}
1 change: 1 addition & 0 deletions rauthy-models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use std::str::FromStr;
pub mod app_state;
pub mod email;
pub mod entity;
pub mod language;
pub mod migration;
pub mod request;
pub mod response;
Expand Down

0 comments on commit 884f599

Please sign in to comment.