Skip to content

Commit

Permalink
Merge pull request #169 from manomayam/webid-ui
Browse files Browse the repository at this point in the history
fix: take turtle as input for custom triples
  • Loading branch information
sebadob committed Nov 13, 2023
2 parents 411393f + d9c86ee commit 55433f4
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 121 deletions.
48 changes: 48 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/src/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import sjcl from "sjcl";
import { decode, encode } from "base64-arraybuffer";

export function buidlWebIdUri(userId) {
return `${window.location.origin}/auth/webid/${userId}/profile`
return `${window.location.origin}/auth/webid/${userId}/profile#me`
}

export function extractFormErrors(err) {
Expand Down
19 changes: 9 additions & 10 deletions rauthy-handlers/src/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -854,17 +854,15 @@ pub async fn get_user_webid(

let id = id.into_inner();
let webid = WebId::find(&data, id).await?;
let user = User::find(&data, webid.user_id).await?;
let user = User::find(&data, webid.user_id.clone()).await?;

let resp = WebIdResponse {
user_id: user.id,
webid,
issuer: data.issuer.clone(),
email: user.email,
expose_email: webid.expose_email,
given_name: user.given_name,
family_name: user.family_name,
language: user.language,
custom_triples: webid.custom_triples,
};

resp.as_turtle()
Expand Down Expand Up @@ -942,12 +940,13 @@ pub async fn put_user_webid_data(
let payload = payload.into_inner();
tracing::debug!("\n\n{:?}\n", payload);

let web_id = WebId {
user_id: id,
custom_triples: payload.custom_triples,
expose_email: payload.expose_email,
};
web_id.validate_custom_triples()?;
let web_id = WebId::try_new(id, payload.custom_triples.as_deref(), payload.expose_email)
.map_err(|e| {
ErrorResponse::new(
ErrorResponseType::BadRequest,
format!("Invalid custom data. {}", e),
)
})?;

WebId::upsert(&data, web_id).await?;

Expand Down
1 change: 1 addition & 0 deletions rauthy-models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ webauthn-rs-proto = { workspace = true }

[dev-dependencies]
pretty_assertions = "1"
rstest = "0.18.2"
tokio-test = "*"
142 changes: 61 additions & 81 deletions rauthy-models/src/entity/webids.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::app_state::AppState;
use actix_web::web;
use rauthy_common::constants::{CACHE_NAME_12HR, PUB_URL_WITH_SCHEME};
use rauthy_common::error_response::{ErrorResponse, ErrorResponseType};
use rauthy_common::error_response::ErrorResponse;
use redhac::{cache_get, cache_get_from, cache_get_value, cache_insert, AckLevel};
use rio_api::formatter::TriplesFormatter;
use rio_api::parser::TriplesParser;
use rio_turtle::{NTriplesParser, TurtleFormatter};
use rio_turtle::{NTriplesFormatter, NTriplesParser, TurtleError, TurtleFormatter, TurtleParser};
use serde::{Deserialize, Serialize};
use sqlx::{query, query_as};
use std::fmt::Debug;
Expand All @@ -14,8 +14,8 @@ use utoipa::ToSchema;
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct WebId {
pub user_id: String,
pub custom_triples: Option<String>,
pub expose_email: bool,
custom_triples: Option<String>,
}

impl WebId {
Expand Down Expand Up @@ -107,104 +107,84 @@ impl WebId {
format!("web_id_{}", user_id)
}

#[inline]
fn clean_up_triple_data(custom_triples: &str) -> String {
// We need to clean up things like linefeeds before the triples parse will be happy
let mut cleaned = custom_triples.replace(['\n', ';'], "");

// Additionally, the parse complains if there is no '.' at the end
if !cleaned.ends_with('.') {
cleaned.push('.');
}

// TODO for some reason, we cannot input data into the parser with ';', which separates
// these triples in the final format. How should we handle this?
// It seems we cannot put in multiple triples at once, even though the `parse_all()`
// is being called

cleaned
}

pub fn try_fmt_triples(
custom_triples: &str,
formatter: &mut TurtleFormatter<Vec<u8>>,
) -> Result<(), ErrorResponse> {
// The parser complains about a lof of things.
// To have a good UX when editing the custom data in the UI, we should not save the
// data cleaned up, but actually return it to the user later again like it was written,
// with all linebreaks, spaces, and so on.
// -> cleanup dynamically here each time before actually parsing it
let triples = Self::clean_up_triple_data(custom_triples);

NTriplesParser::new(triples.as_bytes()).parse_all(&mut |t| {
tracing::debug!("\n\n triple in parse_all: {:?}\n", t);
formatter.format(&t).map_err(|err| {
ErrorResponse::new(
ErrorResponseType::BadRequest,
format!("Cannot format custom Triple {}: {:?}", t, err),
pub fn try_new(
user_id: String,
custom_data_turtle: Option<&str>,
expose_email: bool,
) -> Result<Self, TurtleError> {
let custom_triples = custom_data_turtle
.map(|data| {
let mut ttl_parser = TurtleParser::new(
data.as_bytes(),
Some(
Self::resolve_webid_card_uri(&user_id)
.parse()
.expect("Must be valid iri"),
),
);

let mut ntriples_fmt = NTriplesFormatter::new(Vec::<u8>::new());
ttl_parser.parse_all(&mut |t| {
Ok::<_, TurtleError>(ntriples_fmt.format(&t).expect("Must be valid"))
})?;

Ok::<_, TurtleError>(
String::from_utf8(ntriples_fmt.finish().unwrap())
.expect("Must be valid string."),
)
})
})?;
.transpose()?;

Ok(())
Ok(Self {
user_id,
custom_triples,
expose_email,
})
}

pub fn validate_custom_triples(&self) -> Result<(), ErrorResponse> {
let mut formatter = TurtleFormatter::new(Vec::<u8>::new());
if let Some(triples) = &self.custom_triples {
Self::try_fmt_triples(triples, &mut formatter)?;
pub fn fmt_custom_triples_to_ttl(
&self,
formatter: &mut TurtleFormatter<Vec<u8>>,
) -> Result<(), TurtleError> {
if let Some(custom_triples) = self.custom_triples.as_ref() {
NTriplesParser::new(custom_triples.as_bytes()).parse_all(&mut |t| {
Ok::<_, TurtleError>(formatter.format(&t).expect("Must be valid."))
})
} else {
Ok(())
}

Ok(())
}
}

#[cfg(test)]
mod tests {
use rstest::rstest;

use crate::entity::webids::WebId;

// Tests the validation for a String that comes from the UI account page in the end.
// Whatever input should work in the UI must be passing this test.
// TODO expand this test
#[test]
fn test_custom_triple_validation() {
let mut web_id = WebId {
user_id: "SomeId123".to_string(),
custom_triples: None,
expose_email: false,
};

// success without any triples of course
assert!(web_id.validate_custom_triples().is_ok());

// TODO add more tests here which make sense
web_id.custom_triples = Some(
r#"
#[rstest]
#[case(None)]
#[case(Some(
r#"
<http://localhost:8080/auth/webid/za9UxpH7XVxqrtpEbThoqvn2/profile#me>
<http://www.w3.org/ns/solid/terms#oidcIssuer>
<http://localhost:8080/auth/v1>
<http://localhost:8080/auth/v1> .
"#
.to_string(),
);
assert!(web_id.validate_custom_triples().is_ok());

// TODO for some reason, we cannot input data into the parser with ';', which separates
// these triples in the final format. How should we handle this?
// It seems we cannot put in multiple triples at once, even though the `parse_all()`
// is being called
web_id.custom_triples = Some(
r#"
))]
#[case(Some(
r#"
<http://localhost:8080/auth/webid/za9UxpH7XVxqrtpEbThoqvn2/profile#me>
<http://www.w3.org/ns/solid/terms#oidcIssuer>
<http://localhost:8080/auth/v1>;
<http://www.w3.org/ns/solid/terms#oidcIssuer>
<http://localhost:8080/auth/v1>; .
"#
.to_string(),
);
// helps with debugging the test case
if let Err(err) = web_id.validate_custom_triples() {
eprintln!("{}", err.message);
}
// TODO assert!(web_id.validate_custom_triples().is_ok());
assert!(web_id.validate_custom_triples().is_ok());
))]
fn test_custom_triple_validation(#[case] custom_data_turtle: Option<&str>) {
let user_id = "SomeId123".to_owned();
let expose_email = false;

assert!(WebId::try_new(user_id, custom_data_turtle, expose_email).is_ok());
}
}
3 changes: 1 addition & 2 deletions rauthy-models/src/i18n/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ confirmed, your new address will be updated."#,
web_id_desc: r#"You can configure the fields that should be exposed with your WebID.
This is a feature used by some networks for decentralized logins. If you do not know what it is,
you most probably do not need it."#,
web_id_desc_data:
"You can add custom data fields to your WebID in valid FOAF vocabulary",
web_id_desc_data: "You can add custom data fields to your WebID in valid turtle",
web_id_expert_mode: "Enable Expert Mode",
}
}
Expand Down
Loading

0 comments on commit 55433f4

Please sign in to comment.