Initial QSfera import
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import axios from 'axios';
|
||||
|
||||
import { newHelloRequest } from '../models/hello';
|
||||
import { withClientRequestState } from '../utils';
|
||||
import {
|
||||
ExtendedError,
|
||||
ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS,
|
||||
ERROR_HTTP_UNEXPECTED_RESPONSE_STATE
|
||||
} from '../errors';
|
||||
|
||||
import { handleAxiosError } from './utils';
|
||||
import * as types from './types';
|
||||
|
||||
export function receiveError(error) {
|
||||
return {
|
||||
type: types.RECEIVE_ERROR,
|
||||
error
|
||||
};
|
||||
}
|
||||
|
||||
export function resetHello() {
|
||||
return {
|
||||
type: types.RESET_HELLO
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveHello(hello) {
|
||||
const { success, username, displayName } = hello;
|
||||
|
||||
return {
|
||||
type: types.RECEIVE_HELLO,
|
||||
state: success === true,
|
||||
username,
|
||||
displayName,
|
||||
hello
|
||||
};
|
||||
}
|
||||
|
||||
export function executeHello() {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(resetHello());
|
||||
|
||||
const { flow, query } = getState().common;
|
||||
|
||||
const r = withClientRequestState(newHelloRequest(flow, query));
|
||||
return axios.post('./identifier/_/hello', r, {
|
||||
headers: {
|
||||
'Kopano-Konnect-XSRF': '1'
|
||||
}
|
||||
}).then(response => {
|
||||
switch (response.status) {
|
||||
case 200:
|
||||
// success.
|
||||
return response.data;
|
||||
case 204:
|
||||
// not signed-in.
|
||||
return {
|
||||
success: false,
|
||||
state: response.headers['kopano-konnect-state']
|
||||
};
|
||||
default:
|
||||
// error.
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.state !== r.state) {
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
|
||||
}
|
||||
|
||||
dispatch(receiveHello(response));
|
||||
return Promise.resolve(response);
|
||||
}).catch(error => {
|
||||
error = handleAxiosError(error);
|
||||
|
||||
dispatch(receiveError(error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function retryHello() {
|
||||
return function(dispatch) {
|
||||
dispatch(receiveError(null));
|
||||
|
||||
return dispatch(executeHello());
|
||||
};
|
||||
}
|
||||
|
||||
export function requestLogoff() {
|
||||
return {
|
||||
type: types.REQUEST_LOGOFF
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveLogoff(state) {
|
||||
return {
|
||||
type: types.RECEIVE_LOGOFF,
|
||||
state
|
||||
};
|
||||
}
|
||||
|
||||
export function executeLogoff() {
|
||||
return function(dispatch) {
|
||||
dispatch(resetHello());
|
||||
dispatch(requestLogoff());
|
||||
|
||||
const r = withClientRequestState({});
|
||||
return axios.post('./identifier/_/logoff', r, {
|
||||
headers: {
|
||||
'Kopano-Konnect-XSRF': '1'
|
||||
}
|
||||
}).then(response => {
|
||||
switch (response.status) {
|
||||
case 200:
|
||||
// success.
|
||||
return response.data;
|
||||
default:
|
||||
// error.
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.state !== r.state) {
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
|
||||
}
|
||||
|
||||
dispatch(receiveLogoff(response.success === true));
|
||||
return Promise.resolve(response);
|
||||
}).catch(error => {
|
||||
error = handleAxiosError(error);
|
||||
|
||||
dispatch(receiveError(error));
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
import axios from 'axios';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { newHelloRequest } from '../models/hello';
|
||||
import { withClientRequestState } from '../utils';
|
||||
import {
|
||||
ExtendedError,
|
||||
ERROR_LOGIN_VALIDATE_MISSINGUSERNAME,
|
||||
ERROR_LOGIN_VALIDATE_MISSINGPASSWORD,
|
||||
ERROR_LOGIN_FAILED,
|
||||
ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS,
|
||||
ERROR_HTTP_UNEXPECTED_RESPONSE_STATE
|
||||
} from '../errors';
|
||||
|
||||
import * as types from './types';
|
||||
import { receiveHello } from './common';
|
||||
import { handleAxiosError } from './utils';
|
||||
|
||||
// Modes for logon.
|
||||
export const ModeLogonUsernameEmptyPasswordCookie = '0';
|
||||
export const ModeLogonUsernamePassword = '1';
|
||||
|
||||
export function updateInput(name, value) {
|
||||
return {
|
||||
type: types.UPDATE_INPUT,
|
||||
name,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveValidateLogon(errors) {
|
||||
return {
|
||||
type: types.RECEIVE_VALIDATE_LOGON,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
export function requestLogon(username, password) {
|
||||
return {
|
||||
type: types.REQUEST_LOGON,
|
||||
username,
|
||||
password
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveLogon(logon) {
|
||||
const { success, errors } = logon;
|
||||
|
||||
return {
|
||||
type: types.RECEIVE_LOGON,
|
||||
success,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
export function requestConsent(allow=false) {
|
||||
return {
|
||||
type: allow ? types.REQUEST_CONSENT_ALLOW : types.REQUEST_CONSENT_CANCEL
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveConsent(logon) {
|
||||
const { success, errors } = logon;
|
||||
|
||||
return {
|
||||
type: types.RECEIVE_CONSENT,
|
||||
success,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
export function executeLogon(username, password, mode=ModeLogonUsernamePassword) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(requestLogon(username, password));
|
||||
dispatch(receiveHello({
|
||||
username
|
||||
})); // Reset any hello state on logon.
|
||||
|
||||
const { flow, query } = getState().common;
|
||||
|
||||
// Prepare params based on mode.
|
||||
const params = [];
|
||||
switch (mode) {
|
||||
case ModeLogonUsernamePassword:
|
||||
// Username with password.
|
||||
params.push(username, password, mode);
|
||||
break;
|
||||
|
||||
case ModeLogonUsernameEmptyPasswordCookie:
|
||||
// Username with empty password - this only works when the user is already signed in.
|
||||
params.push(username, '', mode);
|
||||
break;
|
||||
|
||||
// no default
|
||||
}
|
||||
|
||||
const r = withClientRequestState({
|
||||
params: params,
|
||||
hello: newHelloRequest(flow, query)
|
||||
});
|
||||
return axios.post('./identifier/_/logon', r, {
|
||||
headers: {
|
||||
'Kopano-Konnect-XSRF': '1'
|
||||
}
|
||||
}).then(response => {
|
||||
switch (response.status) {
|
||||
case 200:
|
||||
// success.
|
||||
return response.data;
|
||||
case 204:
|
||||
// login failed.
|
||||
return {
|
||||
success: false,
|
||||
state: response.headers['kopano-konnect-state'],
|
||||
errors: {
|
||||
http: new Error(ERROR_LOGIN_FAILED)
|
||||
}
|
||||
};
|
||||
default:
|
||||
// error.
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.state !== r.state) {
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
|
||||
}
|
||||
|
||||
let { hello } = response;
|
||||
if (!hello) {
|
||||
hello = {
|
||||
success: response.success,
|
||||
username
|
||||
};
|
||||
}
|
||||
dispatch(receiveHello(hello));
|
||||
dispatch(receiveLogon(response));
|
||||
return Promise.resolve(response);
|
||||
}).catch(error => {
|
||||
error = handleAxiosError(error);
|
||||
const errors = {
|
||||
http: error
|
||||
};
|
||||
|
||||
dispatch(receiveValidateLogon(errors));
|
||||
return {
|
||||
success: false,
|
||||
errors: errors
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function executeConsent(allow=false, scope='') {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(requestConsent(allow));
|
||||
|
||||
const { query } = getState().common;
|
||||
|
||||
const r = withClientRequestState({
|
||||
allow,
|
||||
scope,
|
||||
client_id: query.client_id || '', // eslint-disable-line camelcase
|
||||
redirect_uri: query.redirect_uri || '', // eslint-disable-line camelcase
|
||||
ref: query.state || '',
|
||||
flow_nonce: query.nonce || '' // eslint-disable-line camelcase
|
||||
});
|
||||
return axios.post('./identifier/_/consent', r, {
|
||||
headers: {
|
||||
'Kopano-Konnect-XSRF': '1'
|
||||
}
|
||||
}).then(response => {
|
||||
switch (response.status) {
|
||||
case 200:
|
||||
// success.
|
||||
return response.data;
|
||||
case 204:
|
||||
// cancel reply.
|
||||
return {
|
||||
success: true,
|
||||
state: response.headers['kopano-konnect-state']
|
||||
};
|
||||
default:
|
||||
// error.
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, response);
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.state !== r.state) {
|
||||
throw new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATE, response);
|
||||
}
|
||||
|
||||
dispatch(receiveConsent(response));
|
||||
return Promise.resolve(response);
|
||||
}).catch(error => {
|
||||
error = handleAxiosError(error);
|
||||
const errors = {
|
||||
http: error
|
||||
};
|
||||
|
||||
dispatch(receiveValidateLogon(errors));
|
||||
return {
|
||||
success: false,
|
||||
errors: errors
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function validateUsernamePassword(username, password, isSignedIn) {
|
||||
return function(dispatch) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const errors = {};
|
||||
|
||||
if (!username) {
|
||||
errors.username = new Error(ERROR_LOGIN_VALIDATE_MISSINGUSERNAME);
|
||||
}
|
||||
if (!password && !isSignedIn) {
|
||||
errors.password = new Error(ERROR_LOGIN_VALIDATE_MISSINGPASSWORD);
|
||||
}
|
||||
|
||||
dispatch(receiveValidateLogon(errors));
|
||||
if (Object.keys(errors).length === 0) {
|
||||
resolve(errors);
|
||||
} else {
|
||||
reject(errors);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function executeLogonIfFormValid(username, password, isSignedIn) {
|
||||
return (dispatch) => {
|
||||
return dispatch(
|
||||
validateUsernamePassword(username, password, isSignedIn)
|
||||
).then(() => {
|
||||
const mode = isSignedIn ? ModeLogonUsernameEmptyPasswordCookie : ModeLogonUsernamePassword;
|
||||
return dispatch(executeLogon(username, password, mode));
|
||||
}).catch((errors) => {
|
||||
return {
|
||||
success: false,
|
||||
errors: errors
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function advanceLogonFlow(success, history, done=false, extraQuery={}) {
|
||||
return (dispatch, getState) => {
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { flow, query, hello } = getState().common;
|
||||
const q = Object.assign({}, query, extraQuery);
|
||||
|
||||
switch (flow) {
|
||||
case 'oauth':
|
||||
case 'consent':
|
||||
case 'oidc':
|
||||
if (hello.details.flow !== flow) {
|
||||
// Ignore requested flow if hello flow does not match.
|
||||
break;
|
||||
}
|
||||
|
||||
if (!done && hello.details.next === 'consent') {
|
||||
history.replace(`/consent${history.location.search}${history.location.hash}`);
|
||||
return;
|
||||
}
|
||||
if (hello.details.continue_uri) {
|
||||
q.prompt = 'none';
|
||||
window.location.replace(hello.details.continue_uri + '?' + queryString.stringify(q));
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Legacy stupid modes.
|
||||
if (q.continue && q.continue.indexOf(document.location.origin) === 0) {
|
||||
window.location.replace(q.continue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Default action.
|
||||
let target = '/welcome';
|
||||
if (history.action === 'REPLACE') {
|
||||
target = target + history.location.search + history.location.hash;
|
||||
}
|
||||
|
||||
dispatch(receiveValidateLogon({})); // XXX(longsleep): hack to reset loading and errors.
|
||||
history.push(target);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
export const RECEIVE_ERROR = 'RECEIVE_ERROR';
|
||||
|
||||
export const RESET_HELLO = 'RESET_HELLO';
|
||||
export const EXECUTE_HELLO = 'EXECUTE_HELLO';
|
||||
export const RECEIVE_HELLO = 'RECEIVE_HELLO';
|
||||
|
||||
export const RECEIVE_VALIDATE_LOGON = 'RECEIVE_VALIDATE_LOGON';
|
||||
export const REQUEST_LOGON = 'REQUEST_LOGON';
|
||||
export const EXECUTE_LOGON = 'EXECUTE_LOGON';
|
||||
export const RECEIVE_LOGON = 'RECEIVE_LOGON';
|
||||
export const UPDATE_INPUT = 'UPDATE_INPUT';
|
||||
|
||||
export const REQUEST_CONSENT_ALLOW = 'REQUEST_CONSENT_ALLOW';
|
||||
export const REQUEST_CONSENT_CANCEL = 'REQUEST_CONSENT_CANCEL';
|
||||
export const EXECUTE_CONSENT = 'EXECUTE_CONSENT';
|
||||
export const RECEIVE_CONSENT = 'RECEIVE_CONSENT';
|
||||
|
||||
export const REQUEST_LOGOFF = 'REQUEST_LOGOFF';
|
||||
export const EXECUTE_LOGOFF = 'EXECUTE_LOGOFF';
|
||||
export const RECEIVE_LOGOFF = 'RECEIVE_LOGOFF';
|
||||
|
||||
export const SERVICE_WORKER_NEW_CONTENT = 'SERVICE_WORKER_NEW_CONTENT';
|
||||
export const SERVICE_WORKER_READY = 'SERVICE_WORKER_READY';
|
||||
export const SERVICE_WORKER_ERROR = 'SERVICE_WORKER_ERROR';
|
||||
export const SERVICE_WORKER_OFFLINE = 'SERVICE_WORKER_OFFLINE';
|
||||
@@ -0,0 +1,18 @@
|
||||
import {
|
||||
ExtendedError,
|
||||
ERROR_HTTP_NETWORK_ERROR,
|
||||
ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS
|
||||
} from '../errors';
|
||||
|
||||
export function handleAxiosError(error) {
|
||||
if (error.request) {
|
||||
// Axios errors.
|
||||
if (error.response) {
|
||||
error = new ExtendedError(ERROR_HTTP_UNEXPECTED_RESPONSE_STATUS, error.response);
|
||||
} else {
|
||||
error = new ExtendedError(ERROR_HTTP_NETWORK_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
Reference in New Issue
Block a user