From 8eb31b984e5e6a5cf5e795c0ad54b68f922728b9 Mon Sep 17 00:00:00 2001 From: Mitchell Gerber Date: Wed, 10 Jan 2018 21:03:30 -0600 Subject: [PATCH] client - get browser fingerprint and set header --- client/@types/all/index.d.ts | 3 +- client/app/axios/axios.ts | 45 +++++++++++++++++++-------- client/app/routes.tsx | 23 +++++++++++++- client/app/services/thread.service.ts | 5 ++- client/app/stores/user-store.ts | 3 +- client/package.json | 2 ++ client/yarn.lock | 8 +++++ 7 files changed, 71 insertions(+), 18 deletions(-) diff --git a/client/@types/all/index.d.ts b/client/@types/all/index.d.ts index 7ea5253..31b2804 100644 --- a/client/@types/all/index.d.ts +++ b/client/@types/all/index.d.ts @@ -1,4 +1,5 @@ // for libraries that don't have types -declare module 'this-is-a-test-module'; +// declare module 'this-is-a-test-module'; +declare module 'fingerprintjs2'; declare module '*.gif'; declare module '*.jpg'; diff --git a/client/app/axios/axios.ts b/client/app/axios/axios.ts index ec8c856..000d0ad 100644 --- a/client/app/axios/axios.ts +++ b/client/app/axios/axios.ts @@ -1,23 +1,43 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; +import fingerprintjs2 from 'fingerprintjs2'; import userStore from '../stores/user-store'; // create our own instance of axios so we can set request headers const ax: AxiosInstance = axios.create(); +export default ax; -// response interceptors -ax.interceptors.response.use( - (config: AxiosResponse) => { - return config; - }, - (error: any) => { - // if code is unauthorized (401) then logout if already logged in - if (error.response.status === 401 && userStore.user) { - userStore.resetUser(); +// setup our axios instance - must be done before app bootstraps +export const initializeAxios = (): Promise => { + return new Promise((resolve: any) => { + // response interceptors + ax.interceptors.response.use( + (config: AxiosResponse) => { + return config; + }, + (error: any) => { + // if code is unauthorized (401) then logout if already logged in + if (error.response.status === 401 && userStore.user) { + userStore.resetUser(); + } + + return Promise.reject(error); + }, + ); + + const user = localStorage.getItem('user'); + + if (user) { + const jwt = JSON.parse(user!).token; + setAuthorizationHeader(jwt); } - return Promise.reject(error); - }, -); + new fingerprintjs2().get((result: string) => { + axios.defaults.headers.common['fp'] = result; + resolve(); + }); + }); +}; + export function setAuthorizationHeader(jwt: string): void { ax.defaults.headers.common['Authorization'] = jwt; @@ -27,4 +47,3 @@ export function resetAuthorizationHeader(): void { ax.defaults.headers.common['Authorization'] = ''; } -export default ax; diff --git a/client/app/routes.tsx b/client/app/routes.tsx index 1a5947a..ce96cfc 100644 --- a/client/app/routes.tsx +++ b/client/app/routes.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { Provider } from 'mobx-react'; +import { initializeAxios } from './axios/axios'; import { Footer, Header } from './components'; import { Forum, Home, NotFound, Oauth, Realms, Thread, UserAccount } from './pages'; import { stores } from './stores/stores'; @@ -10,11 +11,31 @@ import './scss/index.scss'; interface Props {} -interface State {} +interface State { + ready: boolean; +} export class Routes extends React.Component { + constructor(props: Props) { + super(props); + this.state = { + ready: false, + }; + } + + async componentDidMount() { + await initializeAxios(); + this.setState({ ready: true }); + } + public render() { + + // make sure we initialize axios with request headers before we load the app + if (!this.state.ready) { + return
; + } + return ( diff --git a/client/app/services/thread.service.ts b/client/app/services/thread.service.ts index c03b023..b218f97 100644 --- a/client/app/services/thread.service.ts +++ b/client/app/services/thread.service.ts @@ -1,10 +1,13 @@ +import { orderBy } from 'lodash'; import axios from '../axios/axios'; import { ThreadModel } from '../model'; const getCategoryThreads = async (category_id: string): Promise => { try { const res = await axios.get(`/api/thread?category_id=${category_id}`); - return res.data.data; + return orderBy(res.data.data as ThreadModel[], (thread: ThreadModel) => { + return -(new Date(thread.updated_at)); + }); } catch (e) { console.error(e); } diff --git a/client/app/stores/user-store.ts b/client/app/stores/user-store.ts index 5dddf13..7e25d1d 100644 --- a/client/app/stores/user-store.ts +++ b/client/app/stores/user-store.ts @@ -1,6 +1,6 @@ import { action, observable } from 'mobx'; import { UserModel } from '../model'; -import { resetAuthorizationHeader, setAuthorizationHeader } from '../axios/axios'; +import { resetAuthorizationHeader } from '../axios/axios'; export class UserStore { @@ -22,7 +22,6 @@ export class UserStore { const u = localStorage.getItem('user'); if (u) { this.user = JSON.parse(u); - setAuthorizationHeader(this.user!.token); } } diff --git a/client/package.json b/client/package.json index 8b87b81..195d198 100644 --- a/client/package.json +++ b/client/package.json @@ -12,6 +12,7 @@ "author": "Mitchell Gerber", "license": "MIT", "dependencies": { + "@types/fingerprintjs2": "^1.5.1", "@types/lodash": "^4.14.92", "@types/node": "^9.3.0", "@types/query-string": "^5.0.1", @@ -32,6 +33,7 @@ "extract-text-webpack-plugin": "3.0.2", "favicons-webpack-plugin": "^0.0.7", "file-loader": "^1.1.6", + "fingerprintjs2": "^1.5.1", "font-awesome": "^4.7.0", "html-webpack-plugin": "^2.30.1", "lodash": "^4.17.4", diff --git a/client/yarn.lock b/client/yarn.lock index 18a1be8..ec828e8 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +"@types/fingerprintjs2@^1.5.1": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@types/fingerprintjs2/-/fingerprintjs2-1.5.1.tgz#bd4a3f59692824f1d781307d35414d8591ac61e0" + "@types/history@*": version "4.6.2" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.6.2.tgz#12cfaba693ba20f114ed5765467ff25fdf67ddb0" @@ -2463,6 +2467,10 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" +fingerprintjs2@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/fingerprintjs2/-/fingerprintjs2-1.5.1.tgz#010691d425bc37fa0b5a7ec1ae85404bb3f934cb" + flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"