Skip to content

Commit

Permalink
Basic login flow
Browse files Browse the repository at this point in the history
  • Loading branch information
RawToast committed Apr 2, 2018
1 parent f33f86b commit ff41b79
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 83 deletions.
10 changes: 6 additions & 4 deletions dokusho/src/App.re
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ external theme : ReactToolbox.ThemeProvider.theme = "./toolbox/theme";

open Dokusho;
open Types;
open Auth;

type action =
| ChangeRoute(Routes.route);
Expand All @@ -20,13 +21,14 @@ let component = ReasonReact.reducerComponent("App");
let mapUrlToRoute = (url: ReasonReact.Router.url) => {
switch url.path {
| ["callback"] => {
let token = LoginButton.Auth.handleAuth(url);
let token = Auth.handleAuth(url);
ReasonReact.Router.push("/");
Routes.Home(token);
}
| [] => {
Js.Console.log("Home");
let token = LoginButton.Auth.getAccessToken();
if(token == "") Routes.NoAuth else Routes.Home(token);
let token = Auth.getAccessToken();
if(token == "" && !Auth.tokenStillValid()) Routes.NoAuth else Routes.Home(token);
}
| _ => {
Routes.NoAuth;
Expand All @@ -49,7 +51,7 @@ let make = _children => {
<div className="app">
(switch self.state {
| Routes.Home(token) => <Dokusho token=token/>
| Routes.NoAuth => <LoginButton />
| Routes.NoAuth => <Login />
})
</div>
</ReactToolbox.ThemeProvider>
Expand Down
64 changes: 64 additions & 0 deletions dokusho/src/app/Auth.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module Auth {
type generatedAuth0Client = {.
"authorize": [@bs.meth] (unit => unit)
};

type clientOptions = {
.
"domain": string,
"clientID": string,
"redirectUri": string,
"responseType": string,
"scope": string
};

[@bs.module "auth0-js"] [@bs.new] external createClient : (clientOptions => generatedAuth0Client) = "WebAuth";

let matchAccessToken = [%re "/access_token=([^\$&]+)/g"];
let matchExpiresIn = [%re "/expires_in=([^\$&]+)/g"];
let matchIdToken = [%re "/id_token=([^\$&]+)/g"];

let resolveOption = (opt) => switch opt {
| None => ""
| Some(s) => s
};

let resolveRegex = (exp, str) => {
let res = exp |> Js.Re.exec(str);
switch res {
| None => ""
| Some(result) => {
let captures = result |> Js.Re.captures;
switch captures {
| [|_, token|] => token |> Js.Nullable.to_opt |> resolveOption
| _ => ""
};
}
};
};

open Dom.Storage;

let handleAuth = (url: ReasonReact.Router.url) => {

let accessToken = url.hash |> resolveRegex(matchAccessToken);
let idToken = url.hash |> resolveRegex(matchIdToken);
let expiresIn = url.hash |> resolveRegex(matchExpiresIn);
Js.Console.log("Storing auth: " ++ accessToken);
let expiry = Js.Date.now() +. (float_of_string(expiresIn) *. 1000.);
sessionStorage |> setItem("accessToken", accessToken);
sessionStorage |> setItem("id_token", idToken);
sessionStorage |> setItem("expiresIn", string_of_float(expiry));

accessToken;
};

let getIdToken = () => sessionStorage |> getItem("id_token") |> resolveOption;

let getAccessToken = () => (sessionStorage |> getItem("accessToken") |> resolveOption);
let tokenStillValid = () => (sessionStorage
|> getItem("expiresIn")
|> Rationale.Option.fmap(e => float_of_string(e))
|> Rationale.Option.fmap(e => e > Js.Date.now())
|> Rationale.Option.default(false));
};
3 changes: 2 additions & 1 deletion dokusho/src/app/Client.re
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[%raw "require('isomorphic-fetch')"];

open Types;
open Auth;

type serverResponse = {
userId: string,
Expand Down Expand Up @@ -33,7 +34,7 @@ module Client = {

/* Fetches the given user's reading history, or an empty one */
let userHistory = (userId:string) => {
Js.Console.log("Get history: " ++ LoginButton.Auth.getAccessToken());
Js.Console.log("Get history: " ++ Auth.getAccessToken());
Js.Promise.(
Fetch.fetchWithInit(backendURI ++ "/history",
Fetch.RequestInit.make(
Expand Down
21 changes: 6 additions & 15 deletions dokusho/src/app/Entries.re
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
open Types;

let combineEntries = (pt, entries) =>
if (Rationale.RList.any((a => a.kind == pt), entries)) {
entries
|> List.filter(e => e.kind == pt)
|> List.fold_left((a, b) => {id: a.id, kind: pt, value: a.value + b.value}, {id: 0, kind: pt, value: 0})
|> (entry: entry) => (<Entry key=(string_of_int(entry.id)) entry />)
} else ReasonReact.nullElement;

let component = ReasonReact.statelessComponent("Entry");

let make = (~entries: list(entry), _children) => {
...component,
render: (_) =>
render: (_) => {
<div className="entries">
(if (Rationale.RList.any((a => a.kind == Book), entries)) combineEntries(Book, entries) else ReasonReact.nullElement)
(combineEntries(Lyric, entries))
(combineEntries(Manga, entries))
(combineEntries(Net, entries))
(combineEntries(News, entries))
(entries
|> List.map((entry: entry) => <Entry key=(string_of_int(entry.id)) entry />)
|> Array.of_list
|> ReasonReact.arrayToElement)
</div>
}
};

18 changes: 18 additions & 0 deletions dokusho/src/app/Login.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let component = ReasonReact.statelessComponent("Login");

let make = (_) => {
...component,
render: (_) =>
<div>
<div className="title"> (ReasonReact.stringToElement("Dokusho")) </div>
<div className="desc">
<text>
(ReasonReact.stringToElement(
"Dokusho is a japanese reading tracker"
)
)
</text>
</div>
<div className="login"> <LoginButton /> </div>
</div>
};
69 changes: 7 additions & 62 deletions dokusho/src/app/LoginButton.re
Original file line number Diff line number Diff line change
@@ -1,62 +1,4 @@
module Auth {
type generatedAuth0Client = {.
"authorize": [@bs.meth] (unit => unit)
};

type clientOptions = {
.
"domain": string,
"clientID": string,
"redirectUri": string,
"responseType": string,
"scope": string
};

[@bs.module "auth0-js"] [@bs.new] external createClient : (clientOptions => generatedAuth0Client) = "WebAuth";

let matchAccessToken = [%re "/access_token=([^\$&]+)/g"];
let matchExpiresIn = [%re "/expires_in=([^\$&]+)/g"];
let matchIdToken = [%re "/id_token=([^\$&]+)/g"];

let resolveOption = (opt) => switch opt {
| None => ""
| Some(s) => s
};

let resolveRegex = (exp, str) => {
let res = exp |> Js.Re.exec(str);
switch res {
| None => ""
| Some(result) => {
let captures = result |> Js.Re.captures;
switch captures {
| [|_, token|] => token |> Js.Nullable.to_opt |> resolveOption
| _ => ""
};
}
};
};

open Dom.Storage;

let handleAuth = (url: ReasonReact.Router.url) => {

let accessToken = url.hash |> resolveRegex(matchAccessToken);
let idToken = url.hash |> resolveRegex(matchIdToken);
let expiresIn = url.hash |> resolveRegex(matchExpiresIn);
Js.Console.log("Storing auth: " ++ accessToken);

sessionStorage |> setItem("accessToken", accessToken);
sessionStorage |> setItem("id_token", idToken);
sessionStorage |> setItem("expiresIn", expiresIn);

accessToken;
};

let getIdToken = () => sessionStorage |> getItem("id_token") |> resolveOption;

let getAccessToken = () => (sessionStorage |> getItem("accessToken") |> resolveOption);
};
open Auth;

let authOptions = {
"domain": "dokusho.eu.auth0.com",
Expand All @@ -75,9 +17,12 @@ let make = (_) => {
...component,
render: (_) => {
let onLogin = (_event => authClient##authorize());
<ReactToolbox.Button
label="Hey"
<div>
<ReactToolbox.Button
label="login"
onClick=(onLogin)
/>
className="loginbutton"
/>
</div>
}
};
28 changes: 27 additions & 1 deletion dokusho/src/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,43 @@ body {
.title {
display: flex;
flex-direction: column;
font-size: 20px;
font-size: 22px;
align-items: center;
padding: 15px 20px 0px 20px;
}


.login {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 20px 0px 20px;
}

.loginbutton {
display: flex;
flex-direction: column;
font-size: 20px;
align-items: center;
padding: 20px 20px 0px 20px;
}

.dokusho {
align-items: center;
padding-left: 20px;
padding-right: 20px;
}

.desc {
font: 13px "Century Gothic", Futura, sans-serif;
align-items: center;
font-size: 13px;
padding-top: 20px;
padding-left: 20px;
padding-right: 20px;
color: darkslategray;
}

.textinput {
padding-top: 20px;
padding-bottom: 10px;
Expand Down

0 comments on commit ff41b79

Please sign in to comment.