From e77109e3e9ad8cd48c225d2fb9ad607391d2ad5a Mon Sep 17 00:00:00 2001 From: srgooglo Date: Wed, 28 Oct 2020 14:44:15 +0100 Subject: [PATCH] changed auth method to ws --- package-lock.json | 5 + package.json | 1 + src/core/models/user/index.js | 9 +- src/layouts/BaseLayout.js | 11 +- src/models/app.js | 357 +++++++++++++++------------------- src/models/extended.js | 75 +++++++ src/models/user.ts | 70 +++---- src/pages/index.js | 1 + src/pages/login/login.js | 195 ++++++++----------- 9 files changed, 354 insertions(+), 370 deletions(-) diff --git a/package-lock.json b/package-lock.json index be1908b8..eeef1902 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10626,6 +10626,11 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, + "cryptr": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/cryptr/-/cryptr-6.0.2.tgz", + "integrity": "sha512-1TRHI4bmuLIB8WgkH9eeYXzhEg1T4tonO4vVaMBKKde8Dre51J68nAgTVXTwMYXAf7+mV2gBCkm/9wksjSb2sA==" + }, "css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", diff --git a/package.json b/package.json index bb3f631e..f40d766e 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "colors": "^1.4.0", "concat-stream": "^2.0.0", "cookie_js": "^1.4.0", + "cryptr": "^6.0.2", "dotenv": "^8.2.0", "dutier": "^1.1.4", "dva-model-enhance": "^1.2.13", diff --git a/src/core/models/user/index.js b/src/core/models/user/index.js index 98f21f4b..6d18e8cd 100644 --- a/src/core/models/user/index.js +++ b/src/core/models/user/index.js @@ -22,20 +22,13 @@ export const get = { serverKey: serverKey, userToken: access_token, endpoint: endpoints.get_data + }, (err, res) => { return callback(err, res) }, ); }, - posts: parms => { - if (!parms) return false; - const { id } = parms; - - if (!id) { - // core get id data from current session - } - }, basicData: (parms, callback) => { if (!parms) return false diff --git a/src/layouts/BaseLayout.js b/src/layouts/BaseLayout.js index 68f8186b..bc8672fb 100755 --- a/src/layouts/BaseLayout.js +++ b/src/layouts/BaseLayout.js @@ -24,7 +24,7 @@ class BaseLayout extends React.Component { renderLoading = true render() { - const { loading, children, location } = this.props + const { loading, children, location, app } = this.props const Container = LayoutMap[queryLayout(config.layouts, location.pathname)] const currentPath = location.pathname + location.search @@ -38,6 +38,15 @@ class BaseLayout extends React.Component { this.previousPath = currentPath this.renderLoading = false } + + if (app.abortRender) { + return( +
+ {app.abortRender} +
+ ) + } + return ( diff --git a/src/models/app.js b/src/models/app.js index 54912b9a..51197072 100755 --- a/src/models/app.js +++ b/src/models/app.js @@ -6,11 +6,10 @@ import { router, verbosity, appInterface } from 'core/libs' import settings from 'core/libs/settings' import uri_resolver from 'api/lib/uri_resolver' import { queryIndexer } from 'core' +import Cryptr from 'cryptr' import jwt from 'jsonwebtoken' import cookie from 'cookie_js' -import { usePlugins } from 'plugins' -import { SocketConnection, SocketModel } from 'core/libs/socket/index.ts' export default { namespace: 'app', @@ -34,6 +33,7 @@ export default { embedded: false, dispatcher: null, + abortRender: null, controlActive: false, feedOutdated: false, @@ -55,9 +55,8 @@ export default { dispatch({ type: 'updateState', payload: { resolvers: res } }) }) dispatch({ type: 'updateFrames' }) - dispatch({ type: 'handleValidate' }) + dispatch({ type: 'validateSession' }) dispatch({ type: 'socket/createNodeSocket' }) - dispatch({ type: 'queryAuth' }) dispatch({ type: 'query', payload: { dispatcher: dispatch } }) }, setupHistory({ dispatch, history }) { @@ -68,26 +67,23 @@ export default { locationPathname: location.pathname, locationQuery: location.query, }, - }); - }); + }) + }) }, setupRequestCancel({ history }) { history.listen(() => { - const { cancelRequest = new Map() } = window; - + const { cancelRequest = new Map() } = window cancelRequest.forEach((value, key) => { if (value.pathname !== window.location.pathname) { cancelRequest.delete(key); } - }); - }); + }) + }) }, }, effects: { *query({ payload }, { call, put, select }) { - const service = yield select(state => state.app.service_valid) - const session = yield select(state => state.app.session_valid) - const sessionDataframe = yield select(state => state.app.session_data) + const state = yield select(state => state.app) window.PluginGlobals = [] window.Internal = [] @@ -113,114 +109,141 @@ export default { window.location = callback }) - if (!service) { + if (!state.service_valid) { } - - - if (!sessionDataframe && session) { - yield put({ type: 'handleGetUserData' }) - } - }, - *queryAuth({ payload }, { call, put, select }) { - const socket = yield select(state => state.socket) - const state = yield select(state => state) - - - - }, - *logout({ payload }, { call, put, select }) { - const uuid = yield select(state => state.app.session_uuid) - const token = yield select(state => state.app.session_token) - const sk = yield select(state => state.app.server_key) - - session.deauth({ id: uuid, userToken: token, server_key: sk }, (err, res) => { - verbosity([res]) - }) - - yield put({ type: 'sessionErase' }) - }, - *login({ payload }, { call, put, select }) { - if (!payload) return false; - const { user_id, access_token } = payload.authFrame - yield put({ type: 'handleLogin', payload: { user_id, access_token, user_data: payload.dataFrame } }) - }, - *initializePlugins({ payload }, { select }) { - const extended = yield select(state => state.extended) - - if (!payload.array) { - verbosity("Only array map for initialize plugins", "Please read SDK documentation for more info.") - return false - } - try { - usePlugins([payload.array], (err, results) => { - if (err) { - verbosity(["Init error!", err]) - appInterface.notify.error("Plugin initialize error!", err) - return false - } - const rootInit = results[0] - - if (!rootInit.uuid) { - verbosity("Cannot initialize a plugin without UUID.", "Please read SDK documentation for more info.") - appInterface.notify.error("Cannot initialize a plugin without UUID.") - return false - } - - let plugin = { - uuid: null, - version: "n/a", - title: "Blank" - } - plugin = { ...plugin, ...rootInit } - - const rootClass = plugin.payload - let extendedRequire = null - - class extendedPlugin extends rootClass { - constructor(props) { - super(props) + *refreshToken({ callback }, { call, put, select }) { + const state = yield select(state => state.app) + if (state.session_authframe) { + return state.dispatcher({ + type: "socket/use", + scope: "auth", + invoke: "token", + query: { + payload: { + token: state.session_authframe + }, + callback: (callbackResponse) => { + if (typeof (callback) !== "undefined") { + callback(callbackResponse) + } + if (callbackResponse.code == 100) { + verbosity(`updating authframe`) + state.dispatcher({ + type: "setAuth", payload: { + token: callbackResponse.response.token, + authFrame: jwt.decode(callbackResponse.response.token), + dataFrame: state.session_data + } + }) + state.dispatcher({ type: "updateState", payload: { session_valid: true } }) + } else { + verbosity(`this session is no valid, erasing data`) + state.dispatcher({ type: "sessionErase" }) // remove without calling api, its already logged out/invalid + } } } - - if (typeof (plugin.requireExtends) !== "undefined") { - console.log("Extending class with => ", plugin.requireExtends) - - plugin.requireExtends.forEach((e) => { - const RequireFrom = e.from - const RequireImport = e.import - - const existScheme = typeof (RequireImport) !== "undefined" && typeof (RequireFrom) !== "undefined" - if (!existScheme) { - verbosity("Invalid require extension!") - return false - } - - if (Array.isArray(RequireImport)) { - RequireImport.forEach((e) => { - `console`.log(`Importing " ${e} " from [ ${RequireFrom} ]`) - extendedRequire[e] = require(RequireFrom) - }) - } else { - - } - - }) - } - - window.PluginGlobals[plugin.uuid] = new extendedPlugin({ extended, extendedRequire }) - - appInterface.notify.open({ - message: `${plugin.title} v${plugin.version}`, - description: `New plugin is now installed !` - }) }) - } catch (error) { - verbosity("Unexpected catched exception! ", error) - + }else{ + verbosity(`no session_authframe found/valid`) + return false } }, + *logout({ payload }, { put, select }) { + const state = yield select(state => state.app) + + session.deauth({ + id: state.session_uuid, + userToken: state.session_token, + server_key: state.server_key + }, (err, res) => { + verbosity([res]) + state.dispatcher({ type: "sessionErase" }) + }) + + }, + *login({ payload, callback }, { call, put, select }) { + const state = yield select(state => state.app) + if (!payload) return false + const cryptr = new Cryptr(keys.server_key) + + state.dispatcher({ + type: "socket/use", + scope: "auth", + invoke: "authentication", + query: { + payload: { + username: btoa(payload.username), + password: cryptr.encrypt(payload.password) + }, + callback: (callbackResponse) => { + const { authFrame, dataFrame, token } = callbackResponse.response + if (typeof (callback) !== "undefined") { + callback(callbackResponse.code) + } + if (callbackResponse.code == 100) { + state.dispatcher({ type: "setAuth", payload: { authFrame, dataFrame, token } }) + } + } + } + }) + }, + *validateSession({ payload }, { put, select }) { + const state = yield select(state => state.app) + if (state.session_authframe) { + if (typeof (state.session_authframe.exp) == "undefined") { + return false // no support refresh token when is invalid by ws + } + + const now = new Date() + const createdIat = state.session_authframe.iat * 1000 + const expirationTime = (state.session_authframe.iat + state.session_authframe.exp) * 1000 + + const isExpired = expirationTime < now.getTime() + + verbosity([`TOKEN EXPIRES => (${new Date(expirationTime).toLocaleString()})`, `NOW => (${now.toLocaleString()})`]) + + if (isExpired) { + verbosity(`🕒 This session_token is expired`, { color: "red" }) + if (settings("session_noexpire")) { + verbosity(`(session_noexpire) is enabled, refreshing token`) + return state.dispatcher({ type: "refreshToken" }) + } else { + return state.dispatcher({ type: "sessionErase" }) // remove session + } + + } + + if (!state.session_data) { + verbosity(`session_data is not valid but the session is valid, updating from ws`) + state.dispatcher({ type: "updateUserData" }) + } + + state.dispatcher({ type: "updateState", payload: { session_valid: true } }) + } + }, + *updateUserData({ payload }, { put, select }) { + const state = yield select(state => state.app) + state.dispatcher({ + type: "user/get", + payload: { + from: "data" + }, + callback: (callbackResponse) => { + if (callbackResponse.code == 115) { + verbosity(`Cannot update userdata due an data is missing`) + return false + } + try { + sessionStorage.setItem(app_config.session_data_storage, btoa(JSON.stringify(callbackResponse.response))) + state.dispatcher({ type: "updateState", payload: { session_data: callbackResponse.response } }) + } catch (error) { + verbosity([error]) + } + } + }) + }, *updateTheme({ payload }, { put, select }) { if (!payload) return false let container = yield select(state => state.app.app_theme) @@ -245,28 +268,38 @@ export default { }, *updateFrames({ payload }, { select, put }) { try { - const session = yield select(state => state.app.session_valid); let sessionAuthframe = cookie.get(app_config.session_token_storage) - let sessionDataframe = sessionStorage.getItem(app_config.session_data_storage) + let sessionDataframe = atob(sessionStorage.getItem(app_config.session_data_storage)) if (sessionAuthframe) { try { sessionAuthframe = jwt.decode(sessionAuthframe) - yield put({ type: 'handleUpdateAuthFrames', payload: sessionAuthframe }) + yield put({ + type: "updateState", + payload: { + session_authframe: sessionAuthframe, + session_token: sessionAuthframe.access_token, + session_uuid: sessionAuthframe.user_id + } + }) } catch (error) { cookie.remove(app_config.session_token_storage) } } if (sessionDataframe) { try { - sessionDataframe = JSON.parse(atob(sessionDataframe)) - yield put({ type: 'handleUpdateDataFrames', payload: sessionDataframe }) + sessionDataframe = JSON.parse(sessionDataframe) + yield put({ + type: "updateState", + payload: { + session_data: sessionDataframe + } + }) } catch (error) { sessionDataframe = null sessionStorage.clear() } } - } catch (error) { verbosity([error]) } @@ -280,90 +313,18 @@ export default { ...payload, }; }, - handleUpdateAuthFrames(state, { payload }) { - state.session_authframe = payload - state.session_token = payload.session_token, - state.session_uuid = payload.session_uuid - }, - handleUpdateDataFrames(state, { payload }) { - state.session_data = payload - }, - handleValidate(state) { - if (state.session_authframe) { - if (settings("session_noexpire")) { - state.session_valid = true - return - } - const tokenExp = state.session_authframe.exp * 1000 - const tokenExpLocale = new Date(tokenExp).toLocaleString() - const now = new Date().getTime() - - verbosity( - `TOKEN EXP => ${tokenExp} ${settings("session_noexpire") ? '( Infinite )' : `( ${tokenExpLocale} )` - } || NOW => ${now}` - ) - - if (tokenExp < now) { - state.session_valid = false - } else { - state.session_valid = true - } - } - }, - handleLogin(state, { payload }) { + setAuth(state, { payload }) { if (!payload) return false + state.session_token = payload.authFrame.access_token + state.session_uuid = payload.authFrame.user_id + state.session_data = payload.dataFrame + state.session_authframe = jwt.decode(payload.token) - state.session_token = payload.access_token - state.session_uuid = payload.user_id - state.session_data = payload.user_data - const sessionData = JSON.parse(payload.user_data) - - const frame = { - session_uuid: payload.user_id, - session_token: payload.access_token, - avatar: sessionData.avatar, - username: sessionData.username, - attributes: { - isAdmin: sessionData.admin, - isDev: sessionData.dev, - isPro: sessionData.is_pro - } - - } - - jwt.sign(frame, state.server_key, (err, token) => { - if (err) { - verbosity([err]) - return false - } - cookie.set(app_config.session_token_storage, token) - sessionStorage.setItem(app_config.session_data_storage, btoa(payload.user_data)) - state.session_authframe = token - }) + cookie.set(app_config.session_token_storage, payload.token) + sessionStorage.setItem(app_config.session_data_storage, btoa(JSON.stringify(payload.dataFrame))) state.session_valid = true - location.reload() - }, - handleGetUserData(state) { - const frame = { - id: state.session_uuid, - access_token: state.session_token, - serverKey: state.server_key - } - user.get.data(frame, (err, res) => { - if (err) { - verbosity([err]) - } - if (res) { - try { - const session_data = JSON.stringify(res.response) - sessionStorage.setItem(app_config.session_data_storage, btoa(session_data)) - } catch (error) { - verbosity([error]) - } - } - }) }, handleCollapseSidebar(state, { payload }) { state.sidebar_collapsed = payload diff --git a/src/models/extended.js b/src/models/extended.js index 859f9569..88642806 100644 --- a/src/models/extended.js +++ b/src/models/extended.js @@ -19,6 +19,81 @@ export default { effects: { *query({ payload }, { call, put, select }) { + }, + *initializePlugins({ payload }, { select }) { + const extended = yield select(state => state.extended) + + if (!payload.array) { + verbosity("Only array map for initialize plugins", "Please read SDK documentation for more info.") + return false + } + try { + usePlugins([payload.array], (err, results) => { + if (err) { + verbosity(["Init error!", err]) + appInterface.notify.error("Plugin initialize error!", err) + return false + } + const rootInit = results[0] + + if (!rootInit.uuid) { + verbosity("Cannot initialize a plugin without UUID.", "Please read SDK documentation for more info.") + appInterface.notify.error("Cannot initialize a plugin without UUID.") + return false + } + + let plugin = { + uuid: null, + version: "n/a", + title: "Blank" + } + plugin = { ...plugin, ...rootInit } + + const rootClass = plugin.payload + let extendedRequire = null + + class extendedPlugin extends rootClass { + constructor(props) { + super(props) + } + } + + if (typeof (plugin.requireExtends) !== "undefined") { + console.log("Extending class with => ", plugin.requireExtends) + + plugin.requireExtends.forEach((e) => { + const RequireFrom = e.from + const RequireImport = e.import + + const existScheme = typeof (RequireImport) !== "undefined" && typeof (RequireFrom) !== "undefined" + if (!existScheme) { + verbosity("Invalid require extension!") + return false + } + + if (Array.isArray(RequireImport)) { + RequireImport.forEach((e) => { + `console`.log(`Importing " ${e} " from [ ${RequireFrom} ]`) + extendedRequire[e] = require(RequireFrom) + }) + } else { + + } + + }) + } + + window.PluginGlobals[plugin.uuid] = new extendedPlugin({ extended, extendedRequire }) + + appInterface.notify.open({ + message: `${plugin.title} v${plugin.version}`, + description: `New plugin is now installed !` + }) + }) + } catch (error) { + verbosity("Unexpected catched exception! ", error) + + } } }, reducers: { diff --git a/src/models/user.ts b/src/models/user.ts index 4a1dbfe1..8290e80b 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -14,56 +14,36 @@ import cookie from 'cookie_js' export default { namespace: 'user', state: { - - }, - subscriptions: { - setup({ dispatch }) { - dispatch({ type: 'query' }) - }, }, effects: { - *query({ payload }, { call, put, select }) { - const stateConnector = yield select(state => state) - const { server_key, session_token, session_data, session_uuid, session_valid } = stateConnector.app - - yield put({ type: "updateState", payload: { server_key, session_uuid, session_token, session_data, session_valid } }) - }, - *get({ callback, req }, { call, put, select }) { - const state = yield select(state => state.user) - - if (state.session_valid) { - if (!req) { - callback(120, "req params not valid data") - } - user.get[req.fetch]({username: req.username, server_key: state.server_key, access_token: state.session_token }, (err, res) => { - if (err) { - return console.log(err) - } - console.log(res) - const data = res.response - const frame = { - avatar: data.avatar, - can_follow: data.can_follow, - country_id: data.contry_id, - about: data.about, - cover: data.cover, - is_pro: data.is_pro, - lastseen: data.lastseen, - points: data.points, - registered:data.registered, - user_id: data.user_id, - verified: data.verified, - birthday: data.birthday, - details: data.details - } - return callback(false, frame) - }) - }else{ - callback(403, "You need to be logged in to get this data") + *get({ callback, payload }, { call, put, select }) { + const dispatch = yield select(state => state.app.dispatcher) + const state = yield select(state => state) + + if (!payload) { + return callback({code: 115, response: "payload is missing/invalid"}) } + dispatch({ + type: "socket/use", + scope: "users", + invoke: "get", + query: { + payload: { + from: payload.from, + user_id: payload.user_id ?? state.app.session_uuid, + username: payload.username ?? state.app.session_authframe["username"], + userToken: state.app.session_token + }, + callback: (callbackResponse) => { + return callback(callbackResponse) + } + } + }) + + }, *set({ payload }, { call, put, select }) { - + }, }, reducers: { diff --git a/src/pages/index.js b/src/pages/index.js index c3deaa30..dff12680 100755 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -85,6 +85,7 @@ export default class Index extends React.Component {

Misc

{ dispatch({ type: "socket/resetHeader" }) }} > Reset HeaderSocket + { dispatch({ type: "app/refreshToken" }) }} > force refreshToken diff --git a/src/pages/login/login.js b/src/pages/login/login.js index c622208e..7a567db0 100755 --- a/src/pages/login/login.js +++ b/src/pages/login/login.js @@ -19,7 +19,7 @@ import { } from 'components/Icons' import { connect } from 'umi' -@connect(({ app }) => ({ app })) +@connect(({ app, socket }) => ({ app, socket })) export class NormalLoginForm extends React.PureComponent { state = { activeForm: true, @@ -30,28 +30,28 @@ export class NormalLoginForm extends React.PureComponent { step_show: true, swpass: false, } - + next = values => { let a = this.state.step - const b = btoa(Object.values(values).toString()) + const b = Object.values(values).toString() switch (a) { case 1: const payload = { username: Object.values(values).toString() } user.get.basicData(payload, (err, res) => { if (err || !res) return false - if (res.code == 200) { - a++ - this.anim_transition(300) - this.setState({ - step_error: false, - early_data: res.response, - form_rawd_1: b, - step: a, - }) - } - if (res.code == 400) { - this.anim_error() - } + if (res.code == 200) { + a++ + this.anim_transition(300) + this.setState({ + step_error: false, + early_data: res.response, + form_rawd_1: b, + step: a, + }) + } + if (res.code == 400) { + this.anim_error() + } }) return true case 2: @@ -88,77 +88,36 @@ export class NormalLoginForm extends React.PureComponent { this.setState({ step_show: false }) } - - getAuthFrame(payload) { - return new Promise(resolve => { - session.auth(payload, (err, res) => { - if (err) { - - } - if (res) { - verbosity([res]) - - switch (res.code) { - case 200: { - try { - return resolve(res.response) - } catch (error) { - verbosity([error]) - } - break; - } - case 400: { - console.log('Credentials error') - this.setState({ validating: false }) - return this.anim_error() - } - case 500: { - console.log('Server error') - this.setState({ validating: false }) - return this.back() - } - default: { - console.log('Unknown error') - this.setState({ validating: false }) - return this.back() - } - } - - } - }) - }); - } - - getDataFrame(payload) { - return new Promise(resolve => { - user.get.data(payload, (err, res) => { - if(err) { - - } - if (res) { - try { - return resolve(JSON.stringify(res.response)) - } catch (error) { - verbosity([error]) - } - } - }) - - }) - } - - async auth() { + auth() { const { form_rawd_1, form_rawd_2 } = this.state if (!form_rawd_1 || !form_rawd_2) return false this.setState({ step_error: false, validating: true }) - - const authFrame = await this.getAuthFrame({username: form_rawd_1, password: form_rawd_2, server_key: this.props.app.server_key}) - const dataFrame = await this.getDataFrame({user_id: authFrame.user_id, access_token: authFrame.access_token, serverKey: this.props.app.server_key}) - return this.props.dispatch({ - type: 'app/login', - payload: {authFrame, dataFrame} - }); + this.props.dispatch({ + type: 'app/login', + payload: { username: form_rawd_1, password: form_rawd_2 }, + callback: (callbackResponse) => { + console.log(callbackResponse) + this.setState({ validating: false }) + switch (callbackResponse) { + case 100: { + return console.log("login done!") + } + case 400: { + console.log('Credentials error') + return this.anim_error() + } + case 500: { + console.log('Server error') + return this.back() + } + default: { + console.log('Unknown error') + return this.back() + } + } + } + }) } renderState = () => { @@ -174,24 +133,24 @@ export class NormalLoginForm extends React.PureComponent { You can use your YulioID account to login - - } - placeholder="Username or Email" - /> - + + } + placeholder="Username or Email" + /> +