Skip to content

Commit 008b7fd

Browse files
committed
Merge branch 'staging'
2 parents aeff3bd + 9a5fcaf commit 008b7fd

10 files changed

Lines changed: 231 additions & 23 deletions

File tree

src/chayns-info.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { getItem, setItem } from './utils/localStorage';
88

99
import { DEFAULT_LOCATIONID } from './constants/defaults';
1010
import VERSION from './constants/version';
11-
import LOGIN_TAPP_ID from './constants/login-tapp-id';
11+
import { LOGIN_TAPP_ID, LOGIN_TAPP_URL } from './constants/login-tapp';
1212

1313
const consoleLoggerLocation = new ConsoleLogger('loadLocation(chayns-info.js)');
1414
const consoleLoggerTapps = new ConsoleLogger('loadTapps(chayns-info.js)');
@@ -48,7 +48,6 @@ export async function loadLocation(locationId = DEFAULT_LOCATIONID) {
4848
IsMobile: false,
4949
ExclusiveMode: false,
5050
IsFacebook: (document.referrer.indexOf('staticxx.facebook') > -1 || window.location.href.indexOf('fb=1') > -1),
51-
loginTappUrl: locationSettings.loginDialogUrl,
5251
Tapps: [],
5352
LocationPersonID: locationSettings.locationPersonId,
5453
Domain: window.location.host,
@@ -198,7 +197,7 @@ export async function loadTapps(locationId) {
198197

199198
chaynsInfo.Tapps.push({
200199
id: LOGIN_TAPP_ID,
201-
url: chaynsInfo.loginTappUrl,
200+
url: LOGIN_TAPP_URL,
202201
});
203202

204203
globalData.AppInfo.Tapps = chaynsInfo.Tapps;
@@ -217,7 +216,7 @@ export async function loadTapps(locationId) {
217216

218217
chaynsInfo.Tapps = [{
219218
id: LOGIN_TAPP_ID,
220-
url: chaynsInfo.loginTappUrl,
219+
url: LOGIN_TAPP_URL,
221220
}];
222221
globalData.AppInfo.Tapps = chaynsInfo.Tapps;
223222
}

src/chayns-web.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import logger from 'chayns-logger';
22
import loadTapp, { getTappById } from './tapp/custom-tapp';
3-
import { loadLocation, loadTapps, chaynsInfo } from './chayns-info';
3+
import { loadLocation, loadTapps, chaynsInfo, updateUserData } from './chayns-info';
44
import setDynamicStyle from './ui/dynamic-style';
55
import Navigation from './ui/navigation';
66
import { validateTobitAccessToken, stringisEmptyOrWhitespace } from './utils/helper';
77
import { getUrlParameters, set } from './utils/url-parameter';
88
import { decodeTobitAccessToken } from './utils/convert';
9-
import { setTobitAccessToken, getTobitAccessToken } from './json-native-calls/calls/index';
9+
import { setTobitAccessToken } from './json-native-calls/calls/index';
1010
import { showLogin } from './login';
1111
import ConsoleLogger from './utils/console-logger';
1212

13-
import LOGIN_TAPP_ID from './constants/login-tapp-id';
13+
import { LOGIN_TAPP_ID } from './constants/login-tapp';
1414
import { DEFAULT_LOCATIONID, DEFAULT_TAPPID } from './constants/defaults';
1515
import TAPPIDS from './constants/tapp-ids';
1616
import Dialog from './ui/dialog/dialog';
@@ -64,6 +64,16 @@ function startup() {
6464
if (success) {
6565
setDynamicStyle();
6666
init(tappId);
67+
68+
setInterval(async () => {
69+
const token = chaynsInfo.User.TobitAccessToken;
70+
await updateUserData();
71+
72+
const currentTappId = chaynsInfo.getGlobalData().AppInfo.TappSelected.Id;
73+
if (token !== chaynsInfo.User.TobitAccessToken && currentTappId !== LOGIN_TAPP_ID) {
74+
loadTapp(currentTappId); // ToDo: execute "AccessToken Status Change"(66) callback if one exists
75+
}
76+
}, 12 * 60 * 60 * 1000);
6777
}
6878
});
6979
}
@@ -72,8 +82,7 @@ async function init(tappId) {
7282
try {
7383
await loadTapps();
7484

75-
const getTobitAccessTokenRes = await getTobitAccessToken();
76-
const { tobitAccessToken } = getTobitAccessTokenRes.data;
85+
const tobitAccessToken = chaynsInfo.User.TobitAccessToken;
7786

7887
const tapp = getTappById(tappId);
7988

@@ -90,15 +99,12 @@ async function init(tappId) {
9099
if (!tapp) {
91100
consoleLogger.warn('No Tapp found!');
92101

93-
let lang = (navigator.language || navigator.userLanguage).substring(0, 2) || 'en';
94-
if (!(lang.indexOf('de') > -1 || lang.indexOf('en') > -1)) {
95-
lang = 'en';
96-
}
102+
const lang = (navigator.language || navigator.userLanguage).substring(0, 2) || 'en';
97103

98104
let message;
99105
if (lang === 'de') {
100106
message = `Der Tapp "${tappId}" existiert auf der Location "${chaynsInfo.LocationID}" nicht oder Ihnen fehlen die benötigten Berechtigungen.`;
101-
} else { // if lang === 'en'
107+
} else {
102108
message = `The Tapp "${tappId}" does not exist on the location "${chaynsInfo.LocationID}" or you don't have the right permissions to see it.`;
103109
}
104110

src/constants/login-tapp-id.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/constants/login-tapp.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* eslint-disable prefer-destructuring */
2+
import getDavidVersion from '../utils/getDavidVersion';
3+
4+
const loginTapps = [
5+
'https://tapp03.tobit.com/ChaynsWebLightLogin/?AppVersion=##version##&OS=##os##&colormode=##colormode##&color=##color##&apname=##apname##&tappid=-1',
6+
'https://login.chayns.net/chaynsLogin/index.html?AppVersion=##version##&SiteID=##siteid##&OS=##os##&color=##color##&colormode=##colormode##&font=##fontid##&resetCache',
7+
'https://login.chayns.net/chaynsLoginV2/index.html?AppVersion=##version##&SiteID=##siteid##&OS=##os##&color=##color##&colormode=##colormode##&font=##fontid##',
8+
];
9+
let loginTappUrl;
10+
11+
const davidVersion = getDavidVersion();
12+
13+
if (davidVersion !== null) {
14+
if (davidVersion.version < 7435) {
15+
loginTappUrl = loginTapps[0];
16+
} else if (davidVersion.version < 7708) {
17+
loginTappUrl = loginTapps[1];
18+
} else {
19+
loginTappUrl = loginTapps[2];
20+
}
21+
} else {
22+
loginTappUrl = loginTapps[2];
23+
}
24+
25+
export const LOGIN_TAPP_URL = loginTappUrl;
26+
export const LOGIN_TAPP_ID = -1;

src/json-native-calls/calls/get-tobit-access-token.js

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
import { decodeTobitAccessToken } from '../../utils/convert';
2+
import { extendRenewToken, getUserTokenByRenewToken, isTokenValid } from '../../utils/tobitAuth';
13
import executeCall from '../json-native-calls';
24
import errorHandler from '../call-error-handler';
35
import getDefer from '../../utils/defer';
4-
import { getItem } from '../../utils/localStorage';
6+
import { getItem, removeItem, setItem } from '../../utils/localStorage';
57
import { getUrlParameters } from '../../utils/url-parameter';
68
import ConsoleLogger from '../../utils/console-logger';
79

810
const consoleLogger = new ConsoleLogger('getTobitAccessToken(native-call)');
911

12+
const DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
13+
const renewTokenCacheKey = `renewToken_${getUrlParameters().locationid}`;
14+
const userTokenCacheKey = `tobitAccessToken_${getUrlParameters().locationid}`;
1015

1116
export default function getTobitAccessToken() {
1217
try {
@@ -20,11 +25,55 @@ export default function getTobitAccessToken() {
2025
func: defer.resolve,
2126
executeOnlyOnce: true,
2227
},
23-
fallback: () => ({ tobitAccessToken: getItem(`tobitAccessToken_${getUrlParameters().locationid}`) }),
28+
fallback: async () => ({ tobitAccessToken: await getUserToken() })
2429
});
2530

2631
return defer.promise;
2732
} catch (e) {
2833
return errorHandler(e);
2934
}
3035
}
36+
37+
38+
async function getUserToken() {
39+
let renewToken = getItem(renewTokenCacheKey);
40+
if (!renewToken) {
41+
consoleLogger.debug('no renew token in cache');
42+
return null;
43+
}
44+
45+
const renewTokenDecoded = decodeTobitAccessToken(renewToken);
46+
if (renewTokenDecoded.exp * 1000 <= Date.now()) {
47+
consoleLogger.debug('renew token is expired');
48+
removeItem(renewTokenCacheKey);
49+
return null;
50+
} else if (renewTokenDecoded.iat * 1000 < Date.now() - DAY_IN_MILLISECONDS) { // a renew token can first be extended after 24 hours
51+
renewToken = await extendRenewToken(renewToken);
52+
53+
if (renewToken) {
54+
consoleLogger.debug('extended renew token');
55+
setItem(renewTokenCacheKey, renewToken);
56+
} else {
57+
consoleLogger.debug('extend renew token failed');
58+
removeItem(renewTokenCacheKey);
59+
return null;
60+
}
61+
}
62+
63+
const cachedUserToken = getItem(userTokenCacheKey);
64+
65+
if (cachedUserToken) {
66+
const cachedUserTokenDecoded = decodeTobitAccessToken(cachedUserToken);
67+
const cachedUserTokenExpirationTime = new Date(cachedUserTokenDecoded.exp).getTime();
68+
if (cachedUserTokenExpirationTime > Date.now() + DAY_IN_MILLISECONDS && await isTokenValid(cachedUserToken)) {
69+
consoleLogger.debug('took valid user token from cache');
70+
return cachedUserToken;
71+
}
72+
}
73+
74+
consoleLogger.debug('request new user token');
75+
const userToken = await getUserTokenByRenewToken(renewToken);
76+
setItem(userTokenCacheKey, userToken);
77+
78+
return userToken;
79+
}

src/json-native-calls/calls/set-tobit-access-token.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import executeCall from '../json-native-calls';
22
import errorHandler from '../call-error-handler';
33
import getDefer from '../../utils/defer';
4-
import { setItem } from '../../utils/localStorage';
4+
import { getItem, setItem } from '../../utils/localStorage';
55
import { getUrlParameters } from '../../utils/url-parameter';
66
import ConsoleLogger from '../../utils/console-logger';
77

@@ -24,7 +24,7 @@ export default function setTobitAccessToken(tobitAccessToken) {
2424
executeOnlyOnce: true,
2525
},
2626
fallback: () => {
27-
setItem(`tobitAccessToken_${getUrlParameters().locationid}`, tobitAccessToken);
27+
setItem(`renewToken_${getUrlParameters().locationid}`, tobitAccessToken);
2828
},
2929
});
3030

src/json-native-calls/json-native-calls.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,16 @@ export default async function executeCall(config) {
3535
if (typeof window.external !== 'object' || typeof window.external.jsonCall !== 'function') {
3636
if (typeof fallback === 'function') {
3737
consoleLoggerExecute.debug('native-calls are not supported -> fallback.');
38+
39+
let fallbackRes = fallback(data);
40+
41+
if (fallbackRes instanceof Promise) {
42+
fallbackRes = await fallbackRes;
43+
}
44+
3845
func({
3946
parameter: parameter || {},
40-
data: fallback(data) || {},
47+
data: fallbackRes || {},
4148
status: {
4249
code: RESULT_STATUS.FALLBACK
4350
}

src/login.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { closeWindow, resizeWindow, setTobitAccessToken } from './json-native-ca
44
import Navigation from './ui/navigation';
55
import init from './chayns-web';
66
import { getUrlParameters, remove } from './utils/url-parameter';
7-
import LOGIN_TAPP_ID from './constants/login-tapp-id';
7+
import { LOGIN_TAPP_ID } from './constants/login-tapp';
88

99
let prevTappId = null;
1010

src/utils/getDavidVersion.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const DAVID_VERSION_REGEX = /\((\d+),?\s([a-z]+)/gi;
2+
3+
export default function getDavidVersion() {
4+
const userAgent = window.navigator.userAgent.toLowerCase();
5+
6+
if (!userAgent.includes('david')) {
7+
return null;
8+
}
9+
10+
const match = DAVID_VERSION_REGEX.exec(userAgent);
11+
12+
if (!match) {
13+
return null;
14+
}
15+
16+
const [, version, platform] = match;
17+
18+
const isMac = platform === 'macos';
19+
const isWindows = platform === 'windows';
20+
21+
return {
22+
version: parseInt(version, 10),
23+
isMac,
24+
isWindows
25+
};
26+
}

src/utils/tobitAuth.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import logger from 'chayns-logger';
2+
3+
export async function getUserTokenByRenewToken(renewToken) {
4+
const request = await fetch('https://auth.tobit.com/v2/token', {
5+
method: 'POST',
6+
headers: {
7+
authorization: `bearer ${renewToken}`,
8+
'Content-Type': 'application/json'
9+
}
10+
});
11+
12+
if (request.status === 200) {
13+
const body = await request.json();
14+
15+
return body.token;
16+
}
17+
18+
if (request.status !== 401) {
19+
logger.warning({
20+
data: {
21+
'X-Request-Id': request.headers.get('X-Request-Id')
22+
},
23+
ex: {
24+
message: `getUserTokenByRenewToken failed with status code ${request.status}`
25+
},
26+
fileName: 'tobitAuth.js',
27+
section: 'tobitAuth.getUserTokenByRenewToken',
28+
});
29+
}
30+
31+
return null;
32+
}
33+
34+
export async function extendRenewToken(renewToken) {
35+
const request = await fetch('https://auth.tobit.com/v2/token/renew', {
36+
method: 'GET',
37+
headers: {
38+
authorization: `bearer ${renewToken}`,
39+
'Content-Type': 'application/json'
40+
}
41+
});
42+
43+
if (request.status === 200) {
44+
const body = await request.json();
45+
46+
return body.token;
47+
}
48+
if (request.status === 204) {
49+
logger.warning({
50+
data: {
51+
'X-Request-Id': request.headers.get('X-Request-Id')
52+
},
53+
ex: {
54+
message: 'extendRenewToken returned status code 204'
55+
},
56+
fileName: 'tobitAuth.js',
57+
section: 'tobitAuth.extendRenewToken',
58+
});
59+
60+
return renewToken;
61+
}
62+
63+
logger.warning({
64+
data: {
65+
'X-Request-Id': request.headers.get('X-Request-Id')
66+
},
67+
ex: {
68+
message: `extendRenewToken failed with status code ${request.status}`
69+
},
70+
fileName: 'tobitAuth.js',
71+
section: 'tobitAuth.extendRenewToken',
72+
});
73+
return null;
74+
}
75+
76+
export async function isTokenValid(userToken) {
77+
const request = await fetch('https://auth.tobit.com/v2/token/validate', {
78+
method: 'HEAD',
79+
headers: {
80+
authorization: `bearer ${userToken}`
81+
}
82+
});
83+
84+
if (request.status !== 200 && request.status !== 401) {
85+
logger.warning({
86+
data: {
87+
'X-Request-Id': request.headers.get('X-Request-Id')
88+
},
89+
ex: {
90+
message: `getUserTokenByRenewToken failed with status code ${request.status}`
91+
},
92+
fileName: 'tobitAuth.js',
93+
section: 'tobitAuth.getUserTokenByRenewToken',
94+
});
95+
}
96+
97+
return request.status === 200;
98+
}

0 commit comments

Comments
 (0)