fixed socket token refresh

This commit is contained in:
srgooglo 2020-10-29 13:33:01 +01:00
parent 01bbafcd4a
commit 03709378f3
14 changed files with 36334 additions and 211 deletions

36199
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -92,6 +92,7 @@
"redux-thunk": "^2.3.0",
"request": "^2.88.2",
"socket.io-client": "^2.3.0",
"socket.io-promise": "^1.1.2",
"stack-trace": "0.0.10",
"store": "^2.0.12",
"styled-components": "^5.2.0",

View File

@ -129,7 +129,7 @@ export default class PostCard extends React.Component {
}
title={
<div className={styles.post_card_title}>
<h4 onClick={() => router.go(`@${publisher.username}`)} className={styles.titleUser}>
<h4 onClick={() => router.goProfile(publisher.username)} className={styles.titleUser}>
@{publisher.username}
{core.booleanFix(publisher.verified)? (<Icon style={{ color: 'blue' }} component={Icons.verifiedBadge} />) : null}
{core.booleanFix(publisher.nsfw_flag)? (<antd.Tag style={{ margin: '0 0 0 13px' }} color="volcano" > NSFW </antd.Tag> ) : null}

View File

@ -51,6 +51,7 @@ export default class SocketConnection {
}
this.opts = {
isHeader: false,
namespaceOrigin: "/",
hostname: "localhost:5000",
port: "5000",
@ -107,12 +108,11 @@ export default class SocketConnection {
this.setConnectionListeners()
})
}else{
verbosity(`[${this.ioConn.namespaceOrigin}] node is locked, cannot switch the namespace`)
verbosity(`[${this.opts.namespaceOrigin}] node is locked, cannot switch the namespace`)
}
}
}
createConnection(namespace: void) {
const getNode = () => {
const defaultNode = `${this.opts.hostname}${this.opts.namespaceOrigin}`
@ -189,7 +189,7 @@ export default class SocketConnection {
this.ioConn.updateConnectionState(0)
}
this.ioConn.destroy = () => {
this.ioConn.remove = () => {
this.dispatcher({ type: "socket/destroyNode", node: this.opts.namespaceOrigin })
}
@ -200,7 +200,7 @@ export default class SocketConnection {
setConnectionListeners() {
this.ioConn.on('connect', () => {
this.ioConn.updateConnectionState(1)
verbosity(["🔌 Connected to socket"])
verbosity([`🌐 Connected to socket (${this.opts.namespaceOrigin})`])
this.then(this.ioConn) // sending init data
})
@ -218,23 +218,25 @@ export default class SocketConnection {
})
this.ioConn.on('reconnect', (attemptNumber: ioConnTypes) => {
verbosity([`[socket_event] reconnect > Connection reconected with (${attemptNumber}) tries`])
verbosity([` Connection reconected with (${attemptNumber}) tries > [socket_event]`])
this.ioConn.updateConnectionState(1)
})
this.ioConn.on('disconnect', (event: ioConnTypes) => {
verbosity([`[socket_event] disconnect >`, event])
notify.warn("You are offline")
if (this.opts.isHeader) {
notify.warn("You are offline")
}
verbosity([`🔌 Disconnect from socket (${this.opts.namespaceOrigin}) > [socket_event] >`, event])
this.ioConn.updateConnectionState(3)
})
this.ioConn.on('connect_timeout', () => {
verbosity([`[socket_event] connect_timeout >`])
verbosity([`🕘 Socket timeout (${this.opts.namespaceOrigin}) > [socket_event]`])
this.ioConn.updateConnectionState(3)
})
this.ioConn.on('error', (event: ioConnTypes) => {
verbosity([`[socket_event] error >`, event])
verbosity([`❌ Socket throw error (${this.opts.namespaceOrigin}) > [socket_event] >`, event])
})
this.ioConn.on('updateState', (event: ioConnTypes) => {

View File

@ -11,7 +11,6 @@ const defaultSocketAddress = "localhost:7000"
@connect(({ app, socket }) => ({ app, socket }))
export default class SocketDebug extends React.Component {
state = {
resolvers: __legacy__objectToArray(this.props.app.resolvers),
InputRaw: defaultSocketAddress
}

View File

@ -4,7 +4,6 @@ import keys from 'config/app_keys'
import { user, session } from 'core/models'
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'
@ -16,10 +15,8 @@ export default {
state: {
env_proccess: process.env,
server_key: keys.server_key,
resolvers: null,
service_valid: false,
ng_services: false,
session_valid: false,
session_authframe: null,
@ -51,13 +48,10 @@ export default {
} catch (error) {
// nothing
}
uri_resolver().then(res => {
dispatch({ type: 'updateState', payload: { resolvers: res } })
})
dispatch({ type: 'updateFrames' })
dispatch({ type: 'validateSession' })
dispatch({ type: 'socket/createNodeSocket' })
dispatch({ type: 'query', payload: { dispatcher: dispatch } })
dispatch({ type: 'initHeaderSocket' })
dispatch({ type: 'query' })
},
setupHistory({ dispatch, history }) {
history.listen(location => {
@ -108,10 +102,19 @@ export default {
], (callback) => {
window.location = callback
})
},
*initHeaderSocket({ callback }, { call, put, select }) {
const state = yield select(state => state.app)
if (!state.service_valid) {
}
state.dispatcher({
type: 'socket/createNodeSocket', payload: {
locked: true,
isHeader: true
},
then: () => {
state.dispatcher({ type: "updateState", payload: { service_valid: true } })
}
})
},
*refreshToken({ callback }, { call, put, select }) {
const state = yield select(state => state.app)
@ -175,12 +178,14 @@ export default {
password: cryptr.encrypt(payload.password)
},
callback: (callbackResponse) => {
console.log(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 } })
state.dispatcher({ type: "setAuth", payload: { token, authFrame, dataFrame } })
location.reload()
}
}
}
@ -317,11 +322,10 @@ export default {
state.session_uuid = payload.authFrame.session_uuid
state.session_data = payload.dataFrame
state.session_authframe = jwt.decode(payload.token)
state.session_valid = true
cookie.set(app_config.storage_authFrame, payload.token)
sessionStorage.setItem(app_config.storage_dataFrame, btoa(JSON.stringify(payload.dataFrame)))
state.session_valid = true
},
handleCollapseSidebar(state, { payload }) {
state.sidebar_collapsed = payload

View File

@ -72,7 +72,8 @@ export default {
namespaceOrigin: `/${scope}`,
hostname: `${state.socket.socket_address}:${state.socket.socket_port}`,
port: state.socket.socket_port,
reconnectionAttempts: 10
reconnectionAttempts: 10,
forceNew: true
}
new SocketConnection({
@ -80,13 +81,19 @@ export default {
connector: state.app.dispatcher,
payload: opt,
then: (socket) => {
socket._emit(invoke, query.payload, query.callback)
socket._emit(invoke, query.payload, (callback) =>{
new Promise((resolve, reject) => resolve(query.callback(callback))).then(() => {
socket.remove()
})
})
}
})
}else{
state.socket.nodes[scope].ioConn._emit(invoke, query.payload, query.callback)
state.socket.nodes[scope].ioConn._emit(invoke, query.payload, (callback) =>{
query.callback(callback)
state.socket.nodes[scope].ioConn.remove()
})
}
},
*break({ listener, node }, { select, put }) {
if (!node || !listener) {
@ -119,7 +126,7 @@ export default {
}
const state = yield select(state => state.socket)
if (state.nodes[node].connectionState !== "closed") {
console.log("The node is not closed!, closing before destroying")
verbosity("The node is not closed!, closing before destroying")
state.nodes[node].ioConn._close()
}
let updated = {}

View File

@ -30,7 +30,6 @@ export default {
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
},

View File

@ -93,16 +93,18 @@ export default class UserIndexer extends React.Component {
if (matchRegexp) {
this.props.dispatch({
type: "user/get",
req: {
fetch: "profileData",
payload: {
from: "profileData",
username: matchRegexp[1]
},
callback: (err, res) => {
if(err){
this.setState({ ErrorCode: err })
return HandleError({ code: err, msg: res })
callback: (callbackResponse) => {
if(callbackResponse.code == 200){
this.setState({ loading: false, layoutData: callbackResponse.response })
}else{
this.setState({ ErrorCode: callbackResponse.code })
return HandleError({ code: callbackResponse.code, msg: "no message provided" })
}
this.setState({ loading: false, layoutData: res })
}
})
}else{

View File

@ -4,6 +4,7 @@ import endpoints from 'config/endpoints'
import { v3_model } from 'core/libs'
import { connect } from 'umi'
import settings from 'core/libs/settings'
import verbosity from 'core/libs/verbosity'
import { PostCard, PostCreator, Invalid } from 'components'
import * as antd from 'antd'
import styles from './index.less'
@ -12,7 +13,8 @@ import styles from './index.less'
export default class Explore extends React.Component {
state = {
feed: null
feed: null,
renderError: false
}
request(){
@ -26,7 +28,12 @@ export default class Explore extends React.Component {
userToken: this.props.app.session_token
},
callback: (data) => {
this.setState({ feed: data.response })
if (Array.isArray(data.response)) {
this.setState({ feed: data.response })
}else{
verbosity([`error gathering posts >`, data])
this.setState({ renderError: true })
}
}
}
})
@ -51,6 +58,12 @@ export default class Explore extends React.Component {
)
}
if (this.state.renderError){
return (
<Invalid type="SESSION_INVALID" />
)
}
return(
<div className={styles.exploreWrapper}>
<List

View File

@ -9,16 +9,10 @@ import * as antd from 'antd'
import * as Icons from 'components/Icons'
import RegistrationForm from './register.js'
import { NormalLoginForm } from './login.js'
import NormalLoginForm from './login.js'
import GuestSession from './guest.js'
import { app_config } from 'config'
export function transitionToogle() {
window.LoginComponent.setState({
transition: !window.LoginComponent.state.transition,
})
}
import { connect } from 'umi'
const types = [
@ -57,9 +51,9 @@ class Login extends React.Component {
key: 0,
}
renderHelperButtons = () => {
renderHelperButtons() {
return types.map((e) => {
return(
return (
<antd.Button key={e.key} type="link" onClick={() => this.setState({ key: e.key })}>
{e.renderText || "Invalid"}
</antd.Button>
@ -67,46 +61,61 @@ class Login extends React.Component {
})
}
componentDidMount(){
componentDidMount() {
if (this.props.app.session_valid) {
appInterface.notify.info('You have already logged into an account, you can change your account by logging in again')
}
}
componentWillUnmount(){
componentWillUnmount() {
antd.Modal.destroyAll()
}
render() {
renderAccountModal() {
const dispatchLogout = () => this.props.dispatch({ type: "app/logout" })
const openAccountModal = () => {
antd.Modal.confirm({
title: this.props.app.session_data.username,
icon: <antd.Avatar src={this.props.app.session_data.avatar} />,
onOk() {
router.push('/')
},
onCancel() {
dispatchLogout()
},
okText: <><Icons.Home/>Resume</>,
cancelText: <><Icons.Trash/>Logout</>
});
antd.Modal.confirm({
title: this.props.app.session_data.username,
icon: <antd.Avatar src={this.props.app.session_data.avatar} />,
onOk() {
router.push('/')
},
onCancel() {
dispatchLogout()
},
okText: <><Icons.Home />Resume</>,
cancelText: <><Icons.Trash />Logout</>
})
}
renderAccountCard() {
if (this.props.app.session_authframe) {
return (
<div className={styles.third_body}>
<div className={styles.last_auth} onClick={() => this.renderAccountModal()}>
<h4><antd.Avatar size="small" src={this.props.app.session_data.avatar} /> @{this.props.app.session_data.username}</h4>
<h5><Icons.Clock />Last login <antd.Tag>{iatToString(this.props.app.session_authframe.iat || 0)}</antd.Tag></h5>
</div>
</div>
)
}
return null
}
renderTitle() {
return (
<div
className={classnames(styles.login_wrapper, {
[styles.goOut]: this.state.transition,
})}
>
<div className={styles.login_wrapper}>
<div>
<h6><img className={styles.yid_logo} src={'https://api.ragestudio.net/id.svg'} /> YulioID&trade;</h6>
<h2>{types[this.state.key].renderText || "Auth"}</h2>
</div>
)
}
render() {
return (
<div className={styles.login_wrapper}>
<div className={styles.auth_box}>
<div className={styles.left_body}>
<h6>
<img className={styles.yid_logo} src={'https://api.ragestudio.net/id.svg'} /> YulioID&trade;
</h6>
<h2> {types[this.state.key].renderText || "Auth"} </h2>
{this.renderTitle()}
</div>
<div className={styles.right_body}>
{typesRenderMap[this.state.key]}
@ -114,16 +123,8 @@ class Login extends React.Component {
{this.renderHelperButtons()}
</div>
</div>
{this.props.app.session_authframe?
<div className={styles.third_body}>
<div className={styles.last_auth} onClick={() => openAccountModal()}>
<h4><antd.Avatar size="small" src={this.props.app.session_data.avatar} /> @{this.props.app.session_data.username}</h4>
<h5><Icons.Clock/>Last login <antd.Tag>{iatToString(this.props.app.session_authframe.iat || 0)}</antd.Tag></h5>
</div>
</div>
: null}
{this.renderAccountCard()}
</div>
</div>
</div>
)
}

View File

@ -82,8 +82,8 @@
border-radius: 12px 0 0 12px;
box-shadow: 0 10px 20px 0 rgba(51,51,51,0.52);
transition: all 300ms ease-in-out;
}
.right_body{
z-index: 51;
float: right;
@ -97,6 +97,7 @@
box-shadow: 0 10px 20px 0 rgba(51,51,51,0.52);
transition: all 300ms ease-in-out;
}
.third_body{
z-index: 50;
transform: translate(0, -24px);
@ -116,19 +117,17 @@
}
}
.third_body:hover{
background-color: rgba(255, 255, 255, 0.3);
box-shadow: 0 10px 20px 0 rgba(51, 51, 51, 0.8);
transform: translate(0, -16px);
}
.helper_login_btn{
transform: translate(-20px, -14px);
}
.login_helper_footer{
width: 100%;
position: absolute;
@ -159,15 +158,6 @@
}
}
// // Full format
// @media (min-width: 486px){
// .login_wrapper {
// min-height: 580px;
// }
// .auth_box {
// width: 784px;
// }
// }
// Medium format max-width: 830px
@media (min-width: 486px){
@ -200,9 +190,8 @@
.auth_box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: all 150ms ease-in-out;
padding: 70px 16px 40px;
width: 100%;
height: 100%;
@ -230,10 +219,6 @@
}
}
.register_form{
}
@-webkit-keyframes fadeOutLeft {
from {
opacity: 1;

View File

@ -8,8 +8,6 @@ import * as antd from 'antd'
import { session, user } from 'core/models'
import verbosity from 'core/libs/verbosity'
import { Form, Input, Button, Checkbox } from 'antd'
import {
UserOutlined,
@ -20,7 +18,7 @@ import {
import { connect } from 'umi'
@connect(({ app, socket }) => ({ app, socket }))
export class NormalLoginForm extends React.Component {
export default class NormalLoginForm extends React.Component {
state = {
usernameRaw: null,
passwordRaw: null,
@ -42,7 +40,7 @@ export class NormalLoginForm extends React.Component {
user.get.basicData(payload, (err, res) => {
if (res.code == 200) {
step++
this.anim_transition(300)
this.anim_transition(50)
return this.setState({
validating: false,
early_data: res.response,
@ -61,33 +59,39 @@ export class NormalLoginForm extends React.Component {
case 2: {
return this.auth()
}
default:
return false
}
}
back() {
let a = this.state.step
if (a > 1) {
a--
if (this.state.step > 1) {
this.state.step--
this.anim_transition(150)
}
this.setState({ step: a })
this.setState({ step: this.state.step })
}
anim_transition(duration) {
this.setState({ step_show: false })
setTimeout(() => {
this.setState({ step_show: true })
}, duration || 1000)
}, duration || 150)
}
anim_error() {
this.setState({ step_error: true, error_count: (this.state.error_count + 1), validating: false })
}
onChangeField(event) {
if(!this.state) {
return false
}
let updated = this.state
updated[event.target.id] = event.target.value
this.setState(updated)
}
auth() {
const { usernameRaw, passwordRaw } = this.state
if (!usernameRaw || !passwordRaw) return false
@ -97,6 +101,7 @@ export class NormalLoginForm extends React.Component {
type: 'app/login',
payload: { username: usernameRaw, password: passwordRaw },
callback: (callbackResponse) => {
console.log(callbackResponse)
this.setState({ validating: false })
switch (callbackResponse) {
case 100: {
@ -138,7 +143,8 @@ export class NormalLoginForm extends React.Component {
autoFocus
disabled={this.state.validating}
onPressEnter={() => this.next()}
onChange={(e) => { this.setState({ usernameRaw: e.target.value }) }}
id="usernameRaw"
onChange={(e) => this.onChangeField(e)}
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Username or Email"
/>
@ -162,8 +168,9 @@ export class NormalLoginForm extends React.Component {
autoFocus
onPressEnter={() => this.next()}
disabled={this.state.validating}
id="passwordRaw"
prefix={<LockOutlined className="site-form-item-icon" />}
onChange={(e) => { this.setState({ passwordRaw: e.target.value }) }}
onChange={(e) => this.onChangeField(e)}
placeholder="Password"
/>
</Form.Item>
@ -172,20 +179,6 @@ export class NormalLoginForm extends React.Component {
}
}
renderAuthForm() {
return (
<Form
name="signin"
className="login-form"
>
<HeadShake spy={this.state.error_count}>
{this.renderFormItems[this.state.step == 1 ? "username" : "password"]()}
</HeadShake>
</Form>
)
}
renderButtons() {
const PrimaryButton = () => {
return (
@ -207,6 +200,7 @@ export class NormalLoginForm extends React.Component {
className="login-form-button"
onClick={() => this.back()}
>
<SwapLeftOutlined />
Back
</Button>
)
@ -221,7 +215,14 @@ export class NormalLoginForm extends React.Component {
return (
<div className={styles.login_form}>
<Fade left opposite when={this.state.step_show}>
{this.renderAuthForm()}
<Form
name="signin"
className="login-form"
>
<HeadShake spy={this.state.error_count}>
{this.renderFormItems[this.state.step == 1 ? "username" : "password"]()}
</HeadShake>
</Form>
</Fade>
{this.renderButtons()}
</div>

View File

@ -1,13 +1,7 @@
import React from 'react'
import * as Icons from 'components/Icons'
import {
MailOutlined,
TagOutlined,
LockOutlined,
} from '@ant-design/icons'
import styles from './index.less'
import {
Form,
Input,
@ -26,14 +20,34 @@ import { g_recaptcha_key } from 'config/app_keys'
export default class RegistrationForm extends React.Component {
state = {
usernameRaw: null,
passwordRaw: null,
emailRaw: null,
captchaValue: null
}
handleRegister() {
}
onFinish(values) {
console.log('Received values of form: ', values)
}
onCaptcha(values) {
this.setState({ captchaValue: values })
}
onChangeField(event) {
if(!this.state) {
return false
}
let updated = this.state
updated[event.target.id] = event.target.value
this.setState(updated)
}
renderForm() {
return (
<Form
@ -52,7 +66,7 @@ export default class RegistrationForm extends React.Component {
},
]}
>
<Input placeholder="ramdomuser" prefix={<TagOutlined />} />
<Input id="usernameRaw" onChange={(e) => this.onChangeField(e)} placeholder="randomuser" prefix={<Icons.TagOutlined />} />
</Form.Item>
<Form.Item
name="email"
@ -67,7 +81,7 @@ export default class RegistrationForm extends React.Component {
},
]}
>
<Input placeholder="example@no-real.com" prefix={<MailOutlined />} />
<Input id="emailRaw" onChange={(e) => this.onChangeField(e)} placeholder="example@no-real.com" prefix={<Icons.Mail />} />
</Form.Item>
<Form.Item
@ -80,33 +94,7 @@ export default class RegistrationForm extends React.Component {
]}
hasFeedback
>
<Input.Password placeholder="example@no-real.com" prefix={<Icons.Lock />} />
</Form.Item>
<Form.Item
name="confirm"
dependencies={['password']}
hasFeedback
rules={[
{
required: true,
message: 'Please confirm your password!',
},
({ getFieldValue }) => ({
validator(rule, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve()
}
return Promise.reject(
'The two passwords that you entered do not match!'
)
},
}),
]}
>
<Input.Password prefix={<LockOutlined />}
placeholder="example@no-real.com" />
<Input.Password id="passwordRaw" onChange={(e) => this.onChangeField(e)} placeholder="mysupersecretpassword" prefix={<Icons.Lock />} />
</Form.Item>
<Form.Item extra="We must make sure that your are a human.">
@ -142,13 +130,11 @@ export default class RegistrationForm extends React.Component {
]}
>
<Checkbox>
I have read the <a href="">agreement</a>
I have read the <a>agreement</a>
</Checkbox>
</Form.Item>
<Form.Item >
<Button type="primary" htmlType="submit">
Register
</Button>
<Button type="primary"> Register </Button>
</Form.Item>
</Form>
)