Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+133
View File
@@ -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));
});
};
}
+293
View File
@@ -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);
};
}
+25
View File
@@ -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';
+18
View File
@@ -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;
}