8 Commits

Author SHA1 Message Date
philkunz aa5cc9ff81 1.4.2
Docker (tags) / security (push) Failing after 0s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-10-12 23:41:24 +02:00
philkunz 944f689165 fix(UI): Improve text rendering in account navigation. 2024-10-12 23:41:23 +02:00
philkunz 0d613fd634 1.4.1
Docker (tags) / security (push) Failing after 0s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-10-07 15:14:45 +02:00
philkunz a94d1875bd fix(core): Bug fixes and UI enhancements 2024-10-07 15:14:44 +02:00
philkunz 46844fed58 1.4.0
Docker (tags) / security (push) Failing after 0s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-10-07 10:26:21 +02:00
philkunz 03a8536297 feat(core): Refactored plugin and request handling to use idpInterfaces 2024-10-07 10:26:21 +02:00
philkunz 1bfdc67a0e 1.3.1
Docker (tags) / security (push) Failing after 1s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2024-10-07 00:08:53 +02:00
philkunz 3cb79c8dbe fix(account): Fix: updated cleanupViews method to correctly iterate over children. 2024-10-07 00:08:52 +02:00
33 changed files with 430 additions and 199 deletions
+26
View File
@@ -1,5 +1,31 @@
# Changelog # Changelog
## 2024-10-12 - 1.4.2 - fix(UI)
Improve text rendering in account navigation.
- Fix for text alignment in the commit info section of the account navigation.
- Adjusted font settings for better readability.
## 2024-10-07 - 1.4.1 - fix(core)
Bug fixes and UI enhancements
- Updated packages to resolve compatibility issues.
- Optimized the transition animations for the center container.
- Improved the initialization logic for navigating between views.
- Enhanced UI with better organization selection handling.
## 2024-10-07 - 1.4.0 - feat(core)
Refactored plugin and request handling to use 'idpInterfaces'
- Switched from using 'lointReception' to 'idpInterfaces' in various TypeScript sources.
- Updated references to request and data interfaces across multiple modules.
- Improved account handling with new navigation options.
## 2024-10-07 - 1.3.1 - fix(account)
Fix: updated cleanupViews method to correctly iterate over children.
- Fixed the iteration over view container children by converting it to an array before removing children. This resolves potential errors due to incorrect for-loop execution on HTMLCollection.
## 2024-10-06 - 1.3.0 - feat(account) ## 2024-10-06 - 1.3.0 - feat(account)
Implement account and organization management features Implement account and organization management features
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@idp.global/idp.global", "name": "@idp.global/idp.global",
"version": "1.3.0", "version": "1.4.2",
"description": "An identity provider software managing user authentications, registrations, and sessions.", "description": "An identity provider software managing user authentications, registrations, and sessions.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
@@ -21,7 +21,7 @@
"@api.global/typedserver": "^3.0.51", "@api.global/typedserver": "^3.0.51",
"@api.global/typedsocket": "^3.0.1", "@api.global/typedsocket": "^3.0.1",
"@consentsoftware_private/catalog": "^1.0.73", "@consentsoftware_private/catalog": "^1.0.73",
"@design.estate/dees-catalog": "^1.1.13", "@design.estate/dees-catalog": "^1.2.0",
"@design.estate/dees-domtools": "^2.0.64", "@design.estate/dees-domtools": "^2.0.64",
"@design.estate/dees-element": "^2.0.39", "@design.estate/dees-element": "^2.0.39",
"@push.rocks/lik": "^6.0.15", "@push.rocks/lik": "^6.0.15",
+10 -10
View File
@@ -24,8 +24,8 @@ importers:
specifier: ^1.0.73 specifier: ^1.0.73
version: 1.0.77(@types/node@22.7.4) version: 1.0.77(@types/node@22.7.4)
'@design.estate/dees-catalog': '@design.estate/dees-catalog':
specifier: ^1.1.13 specifier: ^1.2.0
version: 1.1.13 version: 1.2.0
'@design.estate/dees-domtools': '@design.estate/dees-domtools':
specifier: ^2.0.64 specifier: ^2.0.64
version: 2.0.64 version: 2.0.64
@@ -420,8 +420,8 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'} engines: {node: '>=12'}
'@design.estate/dees-catalog@1.1.13': '@design.estate/dees-catalog@1.2.0':
resolution: {integrity: sha512-bgxlsu6rfYCTqyC2tDo8dtwFQB2HaINEK4dOSlvEWd9DmDymphxNoHxi5f/4NFY7H8gSIgUoBmk3y/MFU3GoRg==} resolution: {integrity: sha512-QVp36XMzX7PEGKJxVaZ09jPFPV2AVYDhNaP1KRWegoiI/PQ3+YilXC7P7WSTPxBojTi28AdPzt9brpaORFY/Qg==}
'@design.estate/dees-comms@1.0.27': '@design.estate/dees-comms@1.0.27':
resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==} resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==}
@@ -2947,8 +2947,8 @@ packages:
worker-loader: worker-loader:
optional: true optional: true
pdfjs-dist@4.6.82: pdfjs-dist@4.7.76:
resolution: {integrity: sha512-BUOryeRFwvbLe0lOU6NhkJNuVQUp06WxlJVVCsxdmJ4y5cU3O3s3/0DunVdK1PMm7v2MUw52qKYaidhDH1Z9+w==} resolution: {integrity: sha512-8y6wUgC/Em35IumlGjaJOCm3wV4aY/6sqnIT3fVW/67mXsOZ9HWBn8GDKmJUK0GSzpbmX3gQqwfoFayp78Mtqw==}
engines: {node: '>=18'} engines: {node: '>=18'}
peek-readable@5.2.0: peek-readable@5.2.0:
@@ -4864,7 +4864,7 @@ snapshots:
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.9 '@jridgewell/trace-mapping': 0.3.9
'@design.estate/dees-catalog@1.1.13': '@design.estate/dees-catalog@1.2.0':
dependencies: dependencies:
'@design.estate/dees-domtools': 2.0.64 '@design.estate/dees-domtools': 2.0.64
'@design.estate/dees-element': 2.0.39 '@design.estate/dees-element': 2.0.39
@@ -4882,7 +4882,7 @@ snapshots:
highlight.js: 11.10.0 highlight.js: 11.10.0
ibantools: 4.5.1 ibantools: 4.5.1
monaco-editor: 0.52.0 monaco-editor: 0.52.0
pdfjs-dist: 4.6.82 pdfjs-dist: 4.7.76
xterm: 5.3.0 xterm: 5.3.0
xterm-addon-fit: 0.8.0(xterm@5.3.0) xterm-addon-fit: 0.8.0(xterm@5.3.0)
transitivePeerDependencies: transitivePeerDependencies:
@@ -6905,7 +6905,7 @@ snapshots:
'@uptime.link/webwidget@1.1.2': '@uptime.link/webwidget@1.1.2':
dependencies: dependencies:
'@design.estate/dees-catalog': 1.1.13 '@design.estate/dees-catalog': 1.2.0
'@design.estate/dees-domtools': 2.0.64 '@design.estate/dees-domtools': 2.0.64
'@design.estate/dees-element': 2.0.39 '@design.estate/dees-element': 2.0.39
'@design.estate/dees-wcctools': 1.0.90 '@design.estate/dees-wcctools': 1.0.90
@@ -8563,7 +8563,7 @@ snapshots:
dommatrix: 1.0.3 dommatrix: 1.0.3
web-streams-polyfill: 3.3.3 web-streams-polyfill: 3.3.3
pdfjs-dist@4.6.82: pdfjs-dist@4.7.76:
optionalDependencies: optionalDependencies:
canvas: 2.11.2 canvas: 2.11.2
path2d: 0.2.1 path2d: 0.2.1
+1 -1
View File
@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@idp.global/idp.global', name: '@idp.global/idp.global',
version: '1.3.0', version: '1.4.2',
description: 'An identity provider software managing user authentications, registrations, and sessions.' description: 'An identity provider software managing user authentications, registrations, and sessions.'
} }
+2 -2
View File
@@ -3,8 +3,8 @@ import * as path from 'path';
export { path }; export { path };
// Project scope // Project scope
import * as lointReception from '../dist_ts_interfaces/index.js'; import * as idpInterfaces from '../dist_ts_interfaces/index.js';
export { lointReception }; export { idpInterfaces };
// @api.global scope // @api.global scope
import * as typedserver from '@api.global/typedserver'; import * as typedserver from '@api.global/typedserver';
+2 -2
View File
@@ -8,7 +8,7 @@ import { User } from './classes.user.js';
@plugins.smartdata.Manager() @plugins.smartdata.Manager()
export class BillingPlan extends plugins.smartdata.SmartDataDbDoc< export class BillingPlan extends plugins.smartdata.SmartDataDbDoc<
BillingPlan, BillingPlan,
plugins.lointReception.data.IBillingPlan, plugins.idpInterfaces.data.IBillingPlan,
BillingPlanManager BillingPlanManager
> { > {
// STATIC // STATIC
@@ -20,7 +20,7 @@ export class BillingPlan extends plugins.smartdata.SmartDataDbDoc<
public id: string; public id: string;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public data: plugins.lointReception.data.IBillingPlan['data'] = { public data: plugins.idpInterfaces.data.IBillingPlan['data'] = {
type: null, type: null,
organizationId: null, organizationId: null,
lastProcessed: null, lastProcessed: null,
+1 -1
View File
@@ -14,7 +14,7 @@ export class BillingPlanManager {
constructor(receptionRefArg: Reception) { constructor(receptionRefArg: Reception) {
this.receptionRef = receptionRefArg; this.receptionRef = receptionRefArg;
this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_UpdatePaymentMethod>('updatePaymentMethod', async reqDataArg => { this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_UpdatePaymentMethod>('updatePaymentMethod', async reqDataArg => {
const user = await this.receptionRef.userManager.getUserByJwt(reqDataArg.jwtString); const user = await this.receptionRef.userManager.getUserByJwt(reqDataArg.jwtString);
const organization = await this.receptionRef.organizationmanager.COrganization.getInstance({ const organization = await this.receptionRef.organizationmanager.COrganization.getInstance({
id: reqDataArg.orgId, id: reqDataArg.orgId,
+3 -3
View File
@@ -6,7 +6,7 @@ import { JwtManager } from './classes.jwtmanager.js';
* Both need to be unique and both can be changed. * Both need to be unique and both can be changed.
*/ */
@plugins.smartdata.Manager() @plugins.smartdata.Manager()
export class Jwt extends plugins.smartdata.SmartDataDbDoc<Jwt, plugins.lointReception.data.IJwt, JwtManager> { export class Jwt extends plugins.smartdata.SmartDataDbDoc<Jwt, plugins.idpInterfaces.data.IJwt, JwtManager> {
// STATIC // STATIC
public static async createJwtForRefreshToken( public static async createJwtForRefreshToken(
jwtManagerInstance: JwtManager, jwtManagerInstance: JwtManager,
@@ -48,7 +48,7 @@ export class Jwt extends plugins.smartdata.SmartDataDbDoc<Jwt, plugins.lointRece
id: jwt.id, id: jwt.id,
blocked: null, blocked: null,
data: jwt.data, data: jwt.data,
} as plugins.lointReception.data.IJwt); } as plugins.idpInterfaces.data.IJwt);
return jwtString; return jwtString;
} }
@@ -60,7 +60,7 @@ export class Jwt extends plugins.smartdata.SmartDataDbDoc<Jwt, plugins.lointRece
public blocked: boolean = false; public blocked: boolean = false;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public data: plugins.lointReception.data.IJwt['data']; public data: plugins.idpInterfaces.data.IJwt['data'];
public async block() { public async block() {
this.blocked = true; this.blocked = true;
+8 -8
View File
@@ -21,7 +21,7 @@ export class JwtManager {
constructor(receptionRefArg: Reception) { constructor(receptionRefArg: Reception) {
this.receptionRef = receptionRefArg; this.receptionRef = receptionRefArg;
this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler<plugins.lointReception.request.IReq_RefreshJwt>( this.typedrouter.addTypedHandler<plugins.idpInterfaces.request.IReq_RefreshJwt>(
new plugins.typedrequest.TypedHandler( new plugins.typedrequest.TypedHandler(
'refreshJwt', 'refreshJwt',
async (requestArg) => { async (requestArg) => {
@@ -34,7 +34,7 @@ export class JwtManager {
) )
); );
this.typedrouter.addTypedHandler( this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_GetPublicKeyForValidation>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_GetPublicKeyForValidation>(
'getPublicKeyForValidation', 'getPublicKeyForValidation',
async (requestArg) => { async (requestArg) => {
// TODO control backend token // TODO control backend token
@@ -46,7 +46,7 @@ export class JwtManager {
); );
this.typedrouter.addTypedHandler( this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_PushOrGetJwtIdBlocklist>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_PushOrGetJwtIdBlocklist>(
'pushOrGetJwtIdBlocklist', 'pushOrGetJwtIdBlocklist',
async (requestArg) => { async (requestArg) => {
// TODO control backend token // TODO control backend token
@@ -60,7 +60,7 @@ export class JwtManager {
public async pushPublicKeyToClients() { public async pushPublicKeyToClients() {
const targetConnections = const targetConnections =
await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag<plugins.lointReception.tags.ITag_LolePubapi>( await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag<plugins.idpInterfaces.tags.ITag_LolePubapi>(
'lole-reception', 'lole-reception',
{ {
backendToken: '', backendToken: '',
@@ -68,7 +68,7 @@ export class JwtManager {
); );
for (const targetConnection of targetConnections) { for (const targetConnection of targetConnections) {
const pushPublicKeyTr = const pushPublicKeyTr =
this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest<plugins.lointReception.request.IReq_PushPublicKeyForValidation>( this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_PushPublicKeyForValidation>(
'pushPublicKeyForValidation', 'pushPublicKeyForValidation',
targetConnection targetConnection
); );
@@ -80,7 +80,7 @@ export class JwtManager {
public async pushBlockedJwtIdListToClients() { public async pushBlockedJwtIdListToClients() {
const targetConnections = const targetConnections =
await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag<plugins.lointReception.tags.ITag_LolePubapi>( await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag<plugins.idpInterfaces.tags.ITag_LolePubapi>(
'lole-reception', 'lole-reception',
{ {
backendToken: '', backendToken: '',
@@ -88,7 +88,7 @@ export class JwtManager {
); );
for (const targetConnection of targetConnections) { for (const targetConnection of targetConnections) {
const pushPublicKeyTr = const pushPublicKeyTr =
this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest<plugins.lointReception.request.IReq_PushOrGetJwtIdBlocklist>( this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_PushOrGetJwtIdBlocklist>(
'pushOrGetJwtIdBlocklist', 'pushOrGetJwtIdBlocklist',
targetConnection targetConnection
); );
@@ -121,7 +121,7 @@ export class JwtManager {
} }
public async verifyJWTAndGetData(jwtArg: string): Promise<Jwt> { public async verifyJWTAndGetData(jwtArg: string): Promise<Jwt> {
const jwtData: plugins.lointReception.data.IJwt = await this.smartjwtInstance.verifyJWTAndGetData(jwtArg); const jwtData: plugins.idpInterfaces.data.IJwt = await this.smartjwtInstance.verifyJWTAndGetData(jwtArg);
const jwt = await Jwt.getInstance({ const jwt = await Jwt.getInstance({
id: jwtData.id, id: jwtData.id,
}); });
+2 -2
View File
@@ -8,7 +8,7 @@ import { User } from './classes.user.js';
@plugins.smartdata.Manager() @plugins.smartdata.Manager()
export class LoginSession extends plugins.smartdata.SmartDataDbDoc< export class LoginSession extends plugins.smartdata.SmartDataDbDoc<
LoginSession, LoginSession,
plugins.lointReception.data.ILoginSession, plugins.idpInterfaces.data.ILoginSession,
LoginSessionManager LoginSessionManager
> { > {
// ====== // ======
@@ -55,7 +55,7 @@ export class LoginSession extends plugins.smartdata.SmartDataDbDoc<
public id: string; public id: string;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public data: plugins.lointReception.data.ILoginSession['data'] = { public data: plugins.idpInterfaces.data.ILoginSession['data'] = {
userId: null, userId: null,
validUntil: Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ weeks: 1 }), validUntil: Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ weeks: 1 }),
invalidated: false, invalidated: false,
+9 -9
View File
@@ -26,7 +26,7 @@ export class LoginSessionManager {
this.receptionRef = receptionRefArg; this.receptionRef = receptionRefArg;
this.receptionRef.typedrouter.addTypedRouter(this.typedRouter); this.receptionRef.typedrouter.addTypedRouter(this.typedRouter);
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_LoginWithEmailOrUsernameAndPassword>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_LoginWithEmailOrUsernameAndPassword>(
'loginWithEmailOrUsernameAndPassword', 'loginWithEmailOrUsernameAndPassword',
async (requestData) => { async (requestData) => {
let user = await this.receptionRef.userManager.CUser.getInstance({ let user = await this.receptionRef.userManager.CUser.getInstance({
@@ -79,7 +79,7 @@ export class LoginSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_LoginWithEmail>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_LoginWithEmail>(
'loginWithEmail', 'loginWithEmail',
async (requestDataArg) => { async (requestDataArg) => {
logger.log('info', `loginWithEmail requested for: ${requestDataArg.email}`); logger.log('info', `loginWithEmail requested for: ${requestDataArg.email}`);
@@ -121,7 +121,7 @@ export class LoginSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_LoginWithEmailAfterEmailTokenAquired>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_LoginWithEmailAfterEmailTokenAquired>(
'loginWithEmailAfterEmailTokenAquired', 'loginWithEmailAfterEmailTokenAquired',
async (requestArg) => { async (requestArg) => {
const tokenObject = this.emailTokenMap.findSync((itemArg) => { const tokenObject = this.emailTokenMap.findSync((itemArg) => {
@@ -145,7 +145,7 @@ export class LoginSessionManager {
) )
); );
this.typedRouter.addTypedHandler<plugins.lointReception.request.ILogoutRequest>( this.typedRouter.addTypedHandler<plugins.idpInterfaces.request.ILogoutRequest>(
new plugins.typedrequest.TypedHandler('logout', async (requestDataArg) => { new plugins.typedrequest.TypedHandler('logout', async (requestDataArg) => {
const loginSession = await this.CLoginSession.getLoginSessionByRefreshToken(requestDataArg.refreshToken); const loginSession = await this.CLoginSession.getLoginSessionByRefreshToken(requestDataArg.refreshToken);
await loginSession.invalidate(); await loginSession.invalidate();
@@ -153,7 +153,7 @@ export class LoginSessionManager {
}) })
); );
this.typedRouter.addTypedHandler<plugins.lointReception.request.IReq_ExchangeRefreshTokenAndTransferToken>( this.typedRouter.addTypedHandler<plugins.idpInterfaces.request.IReq_ExchangeRefreshTokenAndTransferToken>(
new plugins.typedrequest.TypedHandler( new plugins.typedrequest.TypedHandler(
'exchangeRefreshTokenAndTransferToken', 'exchangeRefreshTokenAndTransferToken',
async (requestDataArg) => { async (requestDataArg) => {
@@ -189,7 +189,7 @@ export class LoginSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_ResetPassword>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_ResetPassword>(
'resetPassword', 'resetPassword',
async (requestDataArg) => { async (requestDataArg) => {
const emailOfPasswordToReset = requestDataArg.email; const emailOfPasswordToReset = requestDataArg.email;
@@ -227,7 +227,7 @@ export class LoginSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_SetNewPassword>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_SetNewPassword>(
'setNewPassword', 'setNewPassword',
async (requestData) => { async (requestData) => {
return { return {
@@ -241,7 +241,7 @@ export class LoginSessionManager {
* returns a device id by simply returning a uuid4 * returns a device id by simply returning a uuid4
*/ */
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_ObtainDeviceId>('obtainDeviceId', async (reqData) => { new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_ObtainDeviceId>('obtainDeviceId', async (reqData) => {
reqData; reqData;
return { return {
deviceId: { deviceId: {
@@ -252,7 +252,7 @@ export class LoginSessionManager {
) )
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_AttachDeviceId>('attachDeviceId', async (reqData) => { new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_AttachDeviceId>('attachDeviceId', async (reqData) => {
// TODO: Blocked by proper JWT handling // TODO: Blocked by proper JWT handling
reqData.jwt; reqData.jwt;
return { return {
+3 -3
View File
@@ -5,7 +5,7 @@ import { User } from './classes.user.js';
@plugins.smartdata.Manager() @plugins.smartdata.Manager()
export class Organization extends plugins.smartdata.SmartDataDbDoc< export class Organization extends plugins.smartdata.SmartDataDbDoc<
Organization, Organization,
plugins.lointReception.data.IOrganization, plugins.idpInterfaces.data.IOrganization,
OrganizationManager OrganizationManager
> { > {
public static async createNewOrganizationForUser( public static async createNewOrganizationForUser(
@@ -28,10 +28,10 @@ export class Organization extends plugins.smartdata.SmartDataDbDoc<
// INSTANCE // INSTANCE
@plugins.smartdata.unI() @plugins.smartdata.unI()
id: plugins.lointReception.data.IOrganization['id']; id: plugins.idpInterfaces.data.IOrganization['id'];
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
data: plugins.lointReception.data.IOrganization['data']; data: plugins.idpInterfaces.data.IOrganization['data'];
public async checkIfUserIsAdmin(userArg: User) { public async checkIfUserIsAdmin(userArg: User) {
const role = await this.manager.receptionRef.roleManager.getRoleForUserAndOrg(userArg, this); const role = await this.manager.receptionRef.roleManager.getRoleForUserAndOrg(userArg, this);
+2 -2
View File
@@ -17,7 +17,7 @@ export class OrganizationManager {
this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler( this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_CreateOrganization>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_CreateOrganization>(
'createOrganization', 'createOrganization',
async (requestArg) => { async (requestArg) => {
const nameIsAvailable = async () => { const nameIsAvailable = async () => {
@@ -64,7 +64,7 @@ export class OrganizationManager {
) )
); );
this.typedrouter.addTypedHandler( this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_GetOrganizationById>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_GetOrganizationById>(
'getOrganizationById', 'getOrganizationById',
async (requestArg) => { async (requestArg) => {
const verifiedJwt = await this.receptionRef.jwtManager.verifyJWTAndGetData( const verifiedJwt = await this.receptionRef.jwtManager.verifyJWTAndGetData(
+1 -1
View File
@@ -68,7 +68,7 @@ export class RegistrationSession {
'announced'; 'announced';
public collectedData: { public collectedData: {
userData: plugins.lointReception.data.IUser['data']; userData: plugins.idpInterfaces.data.IUser['data'];
} = { } = {
userData: { userData: {
username: null, username: null,
@@ -14,7 +14,7 @@ export class RegistrationSessionManager {
this.receptionRef.typedrouter.addTypedRouter(this.typedRouter); this.receptionRef.typedrouter.addTypedRouter(this.typedRouter);
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_FirstRegistration>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_FirstRegistration>(
'firstRegistrationRequest', 'firstRegistrationRequest',
async (requestData) => { async (requestData) => {
// check for exiting User // check for exiting User
@@ -60,7 +60,7 @@ export class RegistrationSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_AfterRegistrationEmailClicked>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_AfterRegistrationEmailClicked>(
'afterRegistrationEmailClicked', 'afterRegistrationEmailClicked',
async (requestData) => { async (requestData) => {
console.log(requestData); console.log(requestData);
@@ -83,7 +83,7 @@ export class RegistrationSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_SetDataForRegistration>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_SetDataForRegistration>(
'setDataForRegistration', 'setDataForRegistration',
async (requestData) => { async (requestData) => {
const registrationSession = await this.registrationSessions.find(async (itemArg) => const registrationSession = await this.registrationSessions.find(async (itemArg) =>
@@ -111,7 +111,7 @@ export class RegistrationSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_MobileVerificationForRegistration>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_MobileVerificationForRegistration>(
'mobileVerificationForRegistration', 'mobileVerificationForRegistration',
async (requestData) => { async (requestData) => {
const registrationSession = await this.registrationSessions.find(async (itemArg) => const registrationSession = await this.registrationSessions.find(async (itemArg) =>
@@ -157,7 +157,7 @@ export class RegistrationSessionManager {
); );
this.typedRouter.addTypedHandler( this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_FinishRegistration>( new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_FinishRegistration>(
'finishRegistration', 'finishRegistration',
async (requestData) => { async (requestData) => {
const registrationSession = await this.registrationSessions.find(async (itemArg) => const registrationSession = await this.registrationSessions.find(async (itemArg) =>
+2 -2
View File
@@ -3,12 +3,12 @@ import * as plugins from '../plugins.js';
@plugins.smartdata.Manager() @plugins.smartdata.Manager()
export class Role extends plugins.smartdata.SmartDataDbDoc< export class Role extends plugins.smartdata.SmartDataDbDoc<
Role, Role,
plugins.lointReception.data.IRole plugins.idpInterfaces.data.IRole
> { > {
@plugins.smartdata.unI() @plugins.smartdata.unI()
id: string; id: string;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
data: plugins.lointReception.data.IRole['data']; data: plugins.idpInterfaces.data.IRole['data'];
} }
+1 -1
View File
@@ -19,7 +19,7 @@ export class RoleManager {
action: 'create' | 'change' | 'delete'; action: 'create' | 'change' | 'delete';
userId: string; userId: string;
organizationId: string; organizationId: string;
role: plugins.lointReception.data.IRole['data']['role']; role: plugins.idpInterfaces.data.IRole['data']['role'];
}) { }) {
let returnRole: Role; let returnRole: Role;
switch (optionsArg.action) { switch (optionsArg.action) {
+3 -3
View File
@@ -8,11 +8,11 @@ import { UserManager } from './classes.usermanager.js';
@plugins.smartdata.Manager() @plugins.smartdata.Manager()
export class User extends plugins.smartdata.SmartDataDbDoc< export class User extends plugins.smartdata.SmartDataDbDoc<
User, User,
plugins.lointReception.data.IUser plugins.idpInterfaces.data.IUser
> { > {
// STATIC // STATIC
public static async createNewUserForUserData( public static async createNewUserForUserData(
userDataArg: plugins.lointReception.data.IUser['data'] userDataArg: plugins.idpInterfaces.data.IUser['data']
): Promise<User> { ): Promise<User> {
const newUser = new User(); const newUser = new User();
newUser.id = plugins.smartunique.shortId(); newUser.id = plugins.smartunique.shortId();
@@ -40,7 +40,7 @@ export class User extends plugins.smartdata.SmartDataDbDoc<
id: string; id: string;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public data: plugins.lointReception.data.IUser['data']; public data: plugins.idpInterfaces.data.IUser['data'];
constructor() { constructor() {
super(); super();
+25 -2
View File
@@ -19,7 +19,7 @@ export class UserManager {
constructor(receptionRefArg: Reception) { constructor(receptionRefArg: Reception) {
this.receptionRef = receptionRefArg; this.receptionRef = receptionRefArg;
this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler<plugins.lointReception.request.IReq_GetRolesAndOrganizationsForUserId>( this.typedrouter.addTypedHandler<plugins.idpInterfaces.request.IReq_GetRolesAndOrganizationsForUserId>(
new plugins.typedrequest.TypedHandler('getRolesAndOrganizationsForUserId', async reqArg => { new plugins.typedrequest.TypedHandler('getRolesAndOrganizationsForUserId', async reqArg => {
console.log('user manager: getting roles and orgs'); console.log('user manager: getting roles and orgs');
const user = await this.getUserByJwtValidation(reqArg.jwt); const user = await this.getUserByJwtValidation(reqArg.jwt);
@@ -33,6 +33,29 @@ export class UserManager {
} }
}) })
) )
this.typedrouter.addTypedHandler<plugins.idpInterfaces.request.IReq_WhoIs>(
new plugins.typedrequest.TypedHandler('whoIs', async reqArg => {
const user = await this.getUserByJwtValidation(reqArg.jwt);
if (!user) {
throw new plugins.typedrequest.TypedResponseError('User not found');
}
return {
user: {
id: user.id,
data: {
name: user.data.name,
username: user.data.username,
email: user.data.email,
mobileNumber: user.data.mobileNumber,
connectedOrgs: user.data.connectedOrgs,
status: null,
password: null,
} as plugins.idpInterfaces.data.IUser['data']
}
}
})
)
} }
/** /**
@@ -51,7 +74,7 @@ export class UserManager {
* faster than the "getUserByJwt" * faster than the "getUserByJwt"
*/ */
public async getUserByJwtValidation(jwtStringArg: string) { public async getUserByJwtValidation(jwtStringArg: string) {
const jwtDataArg: plugins.lointReception.data.IJwt = await this.receptionRef.jwtManager.smartjwtInstance.verifyJWTAndGetData(jwtStringArg); const jwtDataArg: plugins.idpInterfaces.data.IJwt = await this.receptionRef.jwtManager.smartjwtInstance.verifyJWTAndGetData(jwtStringArg);
const resultingUser = await this.CUser.getInstance({ const resultingUser = await this.CUser.getInstance({
id: jwtDataArg.data.userId id: jwtDataArg.data.userId
}); });
+34 -23
View File
@@ -4,19 +4,19 @@ import * as plugins from './plugins.js';
export class IdpClient { export class IdpClient {
// INSTANCE PRIVATE // INSTANCE PRIVATE
private helpers = { private helpers = {
async extractDataFromJwtString(jwtString: string): Promise<plugins.lointReception.data.IJwt> { async extractDataFromJwtString(jwtString: string): Promise<plugins.idpInterfaces.data.IJwt> {
return plugins.webjwt.getDataFromJwtString(jwtString); return plugins.webjwt.getDataFromJwtString(jwtString);
}, },
}; };
// INSTANCE PUBLIC // INSTANCE PUBLIC
public appData: plugins.lointReception.data.IApp; public appData: plugins.idpInterfaces.data.IApp;
public rolesReplaySubject = new plugins.smartrx.rxjs.ReplaySubject(1); public rolesReplaySubject = new plugins.smartrx.rxjs.ReplaySubject(1);
public organizationsReplaySubject = new plugins.smartrx.rxjs.ReplaySubject(1); public organizationsReplaySubject = new plugins.smartrx.rxjs.ReplaySubject(1);
public parsedReceptionUrl: plugins.smarturl.Smarturl; public parsedReceptionUrl: plugins.smarturl.Smarturl;
constructor(receptionBaseUrlArg: string, appDataArg?: plugins.lointReception.data.IApp) { constructor(receptionBaseUrlArg: string, appDataArg?: plugins.idpInterfaces.data.IApp) {
if (receptionBaseUrlArg.endsWith('/')) { if (receptionBaseUrlArg.endsWith('/')) {
receptionBaseUrlArg = receptionBaseUrlArg.slice(0, -1); receptionBaseUrlArg = receptionBaseUrlArg.slice(0, -1);
} }
@@ -78,7 +78,7 @@ export class IdpClient {
public typedrouter = new plugins.typedrequest.TypedRouter(); public typedrouter = new plugins.typedrequest.TypedRouter();
public statusObservable = public statusObservable =
new plugins.smartrx.rxjs.Subject<plugins.lointReception.data.TLoginStatus>(); new plugins.smartrx.rxjs.Subject<plugins.idpInterfaces.data.TLoginStatus>();
public ssoStore = new plugins.webstore.WebStore({ public ssoStore = new plugins.webstore.WebStore({
storeName: 'idpglobalStore', storeName: 'idpglobalStore',
@@ -92,7 +92,7 @@ export class IdpClient {
public async getJwt(): Promise<string> { public async getJwt(): Promise<string> {
return await this.ssoStore.get('idpJwt'); return await this.ssoStore.get('idpJwt');
} }
public async getJwtData(): Promise<plugins.lointReception.data.IJwt> { public async getJwtData(): Promise<plugins.idpInterfaces.data.IJwt> {
return this.helpers.extractDataFromJwtString(await this.getJwt()); return this.helpers.extractDataFromJwtString(await this.getJwt());
} }
@@ -121,13 +121,13 @@ export class IdpClient {
} }
public async refreshJwt(refreshTokenArg?: string): Promise<string> { public async refreshJwt(refreshTokenArg?: string): Promise<string> {
let extractedJwt: plugins.lointReception.data.IJwt; let extractedJwt: plugins.idpInterfaces.data.IJwt;
if (!refreshTokenArg) { if (!refreshTokenArg) {
extractedJwt = await this.helpers.extractDataFromJwtString(await this.getJwt()); extractedJwt = await this.helpers.extractDataFromJwtString(await this.getJwt());
} }
const refreshJwtReq = const refreshJwtReq =
new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_RefreshJwt>( new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_RefreshJwt>(
this.parsedReceptionUrl.toString(), this.parsedReceptionUrl.toString(),
'refreshJwt' 'refreshJwt'
); );
@@ -146,11 +146,11 @@ export class IdpClient {
/** /**
* can be used to switch between pages * can be used to switch between pages
*/ */
public async getTransferToken(appDataArg?: plugins.lointReception.data.IApp): Promise<string> { public async getTransferToken(appDataArg?: plugins.idpInterfaces.data.IApp): Promise<string> {
const jwt = await this.performJwtHousekeeping(); const jwt = await this.performJwtHousekeeping();
const extractedJwt = await this.helpers.extractDataFromJwtString(jwt); const extractedJwt = await this.helpers.extractDataFromJwtString(jwt);
const getTransferToken = const getTransferToken =
new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_ExchangeRefreshTokenAndTransferToken>( new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_ExchangeRefreshTokenAndTransferToken>(
this.parsedReceptionUrl.toString(), this.parsedReceptionUrl.toString(),
'exchangeRefreshTokenAndTransferToken' 'exchangeRefreshTokenAndTransferToken'
); );
@@ -188,7 +188,7 @@ export class IdpClient {
const transferToken = url.searchParams['transfertoken']; const transferToken = url.searchParams['transfertoken'];
if (transferToken) { if (transferToken) {
const getTransferToken = const getTransferToken =
new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_ExchangeRefreshTokenAndTransferToken>( new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_ExchangeRefreshTokenAndTransferToken>(
this.parsedReceptionUrl.toString(), this.parsedReceptionUrl.toString(),
'exchangeRefreshTokenAndTransferToken' 'exchangeRefreshTokenAndTransferToken'
); );
@@ -219,7 +219,8 @@ export class IdpClient {
} }
/** /**
* forces the current user to login * determines if the user is logged in
* accepts boolean to optionally require login
* @param requireLoginArg * @param requireLoginArg
* @returns * @returns
*/ */
@@ -256,22 +257,17 @@ export class IdpClient {
* logs out the current user * logs out the current user
*/ */
public async logout() { public async logout() {
const urlInstance = plugins.smarturl.Smarturl.createFromUrl('https://sso.workspace.global/', { const idpLogoutUrl = this.parsedReceptionUrl.clone().set('path', '/logout');
searchParams: { if (!globalThis.location.href.startsWith(idpLogoutUrl.origin)) {
appdata: plugins.smartjson.stringifyBase64(this.appData),
action: 'logout',
},
});
if (!globalThis.location.href.startsWith('https://sso.workspace.global/')) {
// we are somewhere in an app // we are somewhere in an app
await this.deleteJwt(); await this.deleteJwt();
globalThis.location.href = urlInstance.toString(); globalThis.location.href = idpLogoutUrl.toString();
} else { } else {
// we are in the sso page // we are in the sso page
await this.enableTypedSocket(); await this.enableTypedSocket();
console.log(`logging out against ${this.parsedReceptionUrl.toString()}`); console.log(`logging out against ${this.parsedReceptionUrl.toString()}`);
const logoutTr = const logoutTr =
this.typedsocket.createTypedRequest<plugins.lointReception.request.ILogoutRequest>( this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.ILogoutRequest>(
'logout' 'logout'
); );
await logoutTr.fire({ await logoutTr.fire({
@@ -285,6 +281,9 @@ export class IdpClient {
} else { } else {
console.error('no appData provided. Not redirecting after logout.'); console.error('no appData provided. Not redirecting after logout.');
} }
if (window.location.href.startsWith(idpLogoutUrl.origin)) {
window.location.href = this.parsedReceptionUrl.origin;
}
} }
} }
@@ -316,7 +315,7 @@ export class IdpClient {
) { ) {
await this.typedsocketDeferred.promise; await this.typedsocketDeferred.promise;
const validateOrg = const validateOrg =
this.typedsocket.createTypedRequest<plugins.lointReception.request.IReq_CreateOrganization>( this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_CreateOrganization>(
'createOrganization' 'createOrganization'
); );
const response = await validateOrg.fire({ const response = await validateOrg.fire({
@@ -336,7 +335,7 @@ export class IdpClient {
console.log('idpclient: getting roles and orgs...'); console.log('idpclient: getting roles and orgs...');
await this.typedsocketDeferred.promise; await this.typedsocketDeferred.promise;
const rolesAndOrganizationsForUserId = const rolesAndOrganizationsForUserId =
this.typedsocket.createTypedRequest<plugins.lointReception.request.IReq_GetRolesAndOrganizationsForUserId>( this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_GetRolesAndOrganizationsForUserId>(
'getRolesAndOrganizationsForUserId' 'getRolesAndOrganizationsForUserId'
); );
const response = await rolesAndOrganizationsForUserId.fire({ const response = await rolesAndOrganizationsForUserId.fire({
@@ -352,7 +351,7 @@ export class IdpClient {
public async updatePaddleCheckoutId(orgIdArg: string, checkoutIdArg: string) { public async updatePaddleCheckoutId(orgIdArg: string, checkoutIdArg: string) {
await this.typedsocketDeferred.promise; await this.typedsocketDeferred.promise;
const updateBillingPlan = const updateBillingPlan =
this.typedsocket.createTypedRequest<plugins.lointReception.request.IReq_UpdatePaymentMethod>( this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_UpdatePaymentMethod>(
'updatePaymentMethod' 'updatePaymentMethod'
); );
const response = await updateBillingPlan.fire({ const response = await updateBillingPlan.fire({
@@ -364,4 +363,16 @@ export class IdpClient {
}); });
return response; return response;
} }
public async whoIs() {
await this.typedsocketDeferred.promise;
const whoIs =
this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_WhoIs>(
'whoIs'
);
const response = await whoIs.fire({
jwt: await this.getJwt(),
});
return response;
}
} }
+7 -7
View File
@@ -11,21 +11,21 @@ export class IdpRequests {
} }
public get afterRegistrationEmailClicked () { public get afterRegistrationEmailClicked () {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_AfterRegistrationEmailClicked>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_AfterRegistrationEmailClicked>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'afterRegistrationEmailClicked' 'afterRegistrationEmailClicked'
); );
} }
public get setData() { public get setData() {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_SetDataForRegistration>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_SetDataForRegistration>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'setDataForRegistration' 'setDataForRegistration'
); );
} }
public get mobileNumberVerification () { public get mobileNumberVerification () {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_MobileVerificationForRegistration>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_MobileVerificationForRegistration>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'mobileVerificationForRegistration' 'mobileVerificationForRegistration'
); );
@@ -33,28 +33,28 @@ export class IdpRequests {
public get finishRegistration() { public get finishRegistration() {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_FinishRegistration>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_FinishRegistration>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'finishRegistration' 'finishRegistration'
); );
} }
public get loginWithUserNameAndPassword () { public get loginWithUserNameAndPassword () {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_LoginWithEmailOrUsernameAndPassword>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_LoginWithEmailOrUsernameAndPassword>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'loginWithEmailOrUsernameAndPassword' 'loginWithEmailOrUsernameAndPassword'
); );
} }
public get obtainJwt () { public get obtainJwt () {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_RefreshJwt>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_RefreshJwt>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'refreshJwt' 'refreshJwt'
); );
} }
public get obtainOneTimeToken () { public get obtainOneTimeToken () {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_ExchangeRefreshTokenAndTransferToken>( return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_ExchangeRefreshTokenAndTransferToken>(
this.idpClientArg.parsedReceptionUrl.toString(), this.idpClientArg.parsedReceptionUrl.toString(),
'exchangeRefreshTokenAndTransferToken' 'exchangeRefreshTokenAndTransferToken'
); );
+2 -2
View File
@@ -1,7 +1,7 @@
// losslessone_private scope // losslessone_private scope
import * as lointReception from '../dist_ts_interfaces/index.js'; import * as idpInterfaces from '../dist_ts_interfaces/index.js';
export { lointReception }; export { idpInterfaces };
// apiglobal scope // apiglobal scope
import * as typedrequest from '@api.global/typedrequest'; import * as typedrequest from '@api.global/typedrequest';
@@ -74,3 +74,13 @@ export interface IReq_GetRolesAndOrganizationsForUserId
organizations: data.IOrganization[]; organizations: data.IOrganization[];
}; };
} }
export interface IReq_WhoIs {
method: 'whoIs';
request: {
jwt: string;
};
response: {
user: data.IUser;
};
}
+1 -1
View File
@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@idp.global/idp.global', name: '@idp.global/idp.global',
version: '1.3.0', version: '1.4.2',
description: 'An identity provider software managing user authentications, registrations, and sessions.' description: 'An identity provider software managing user authentications, registrations, and sessions.'
} }
+17 -1
View File
@@ -102,7 +102,7 @@ export class IdpAccountContent extends DeesElement {
const viewcontainer: HTMLDivElement = this.shadowRoot.querySelector('.viewcontainer'); const viewcontainer: HTMLDivElement = this.shadowRoot.querySelector('.viewcontainer');
const cleanupViews = async () => { const cleanupViews = async () => {
for (const child of viewcontainer.children) { for (const child of Array.from(viewcontainer.children)) {
viewcontainer.removeChild(child); viewcontainer.removeChild(child);
} }
}; };
@@ -110,6 +110,16 @@ export class IdpAccountContent extends DeesElement {
viewcontainer.append(new views.BaseView()); viewcontainer.append(new views.BaseView());
console.log(`loaded base view`); console.log(`loaded base view`);
this.subrouter.on('', async () => {
viewcontainer.classList.add('changing');
await this.domtools.convenience.smartdelay.delayFor(300);
console.log('We are viewing the account overview');
await cleanupViews();
viewcontainer.append(new views.BaseView());
viewcontainer.classList.remove('changing');
await this.domtools.convenience.smartdelay.delayFor(300);
});
this.subrouter.on('/org/:orgName/billing', async () => { this.subrouter.on('/org/:orgName/billing', async () => {
viewcontainer.classList.add('changing'); viewcontainer.classList.add('changing');
await this.domtools.convenience.smartdelay.delayFor(300); await this.domtools.convenience.smartdelay.delayFor(300);
@@ -121,5 +131,11 @@ export class IdpAccountContent extends DeesElement {
}); });
this.subrouter._handleRouteState(); this.subrouter._handleRouteState();
this.registerGarbageFunction(async () => {
this.subrouter.destroy();
})
} }
} }
+110 -30
View File
@@ -7,11 +7,14 @@ import {
unsafeCSS, unsafeCSS,
css, css,
type TemplateResult, type TemplateResult,
subscribe subscribe,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as plugins from '../../plugins.js'; import * as plugins from '../../plugins.js';
import * as states from '../../states/accountstate.js'; import * as states from '../../states/accountstate.js';
import { IdpState } from '../../states/idp.state.js';
import { commitinfo } from '../../../dist_ts/00_commitinfo_data.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -25,19 +28,19 @@ export class LeleAccountNavigation extends DeesElement {
public options: { text: string; id: string }[] = [ public options: { text: string; id: string }[] = [
{ {
id: '1', id: '1',
text: 'Properties' text: 'Apps',
}, },
{ {
id: '2', id: '2',
text: 'Users' text: 'Users',
}, },
{ {
id: '3', id: '3',
text: 'Activity' text: 'Activity',
}, },
{ {
id: '4', id: '4',
text: 'Billing & Subscription' text: 'Billing & Subscription',
}, },
]; ];
@@ -53,20 +56,52 @@ export class LeleAccountNavigation extends DeesElement {
color: ${cssManager.bdTheme('#333', '#fff')}; color: ${cssManager.bdTheme('#333', '#fff')};
padding: 10px; padding: 10px;
padding-left: 0px; padding-left: 0px;
background: ${cssManager.bdTheme('#eeeeeb', '#111')}; background: ${cssManager.bdTheme('#eeeeeb', '#000')};
border-right: ${cssManager.bdTheme('1px solid #ccc', '')}; border-right: ${cssManager.bdTheme('1px solid #ccc', '1px solid #111')};
} }
:host([hidden]) { :host([hidden]) {
display: none; display: none;
} }
.logo {
font-family: 'Cal Sans';
letter-spacing: 0.0125em;
font-size: 16px;
text-align: center;
padding: 16px 0px 16px 0px;
margin: -8px -8px -16px 0px;
border-bottom: 1px solid #111111;
cursor: default;
position: relative;
z-index: 10;
}
.logo:hover {
background: ${unsafeCSS(plugins.deesCatalog.colors.dark.blue)};
}
.commitinfo {
text-align: center;
position: absolute;
bottom: 0px;
left: 0px;
font-family: 'Intel One Mono';
width: 100%;
font-size: 12px;
padding: 8px;
border-top: ${cssManager.bdTheme('1px solid #ccc', '1px solid #333')};
color: ${cssManager.bdTheme('#666', '#ccc')};
}
.navigationGroupLabel { .navigationGroupLabel {
width: min-content; width: min-content;
white-space: nowrap; white-space: nowrap;
text-transform: uppercase; text-transform: uppercase;
font-size: 12px; font-size: 12px;
font-weight: 300; font-weight: 300;
border-bottom: 1px dotted #666; border-bottom: 1px solid;
border-image: linear-gradient(to right, orange, #44444400) 1;
color: ${cssManager.bdTheme('#666', '#ccc')};
margin-bottom: 5px; margin-bottom: 5px;
padding-top: 32px; padding-top: 32px;
padding-left: 10px; padding-left: 10px;
@@ -80,11 +115,12 @@ export class LeleAccountNavigation extends DeesElement {
padding: 8px; padding: 8px;
padding-left: 10px; padding-left: 10px;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 14px;
} }
.navigationOption:hover { .navigationOption:hover {
cursor: pointer; cursor: default;
background: ${cssManager.bdTheme('#bbb', '#333')}; background: ${cssManager.bdTheme('#bbb', plugins.deesCatalog.colors.dark.blue)};
} }
dees-input-dropdown { dees-input-dropdown {
margin-top: 16px; margin-top: 16px;
@@ -94,24 +130,64 @@ export class LeleAccountNavigation extends DeesElement {
`, `,
]; ];
public async getAccountRouter() {
const host = (this.getRootNode() as any).host;
return (host as any).subrouter;
}
public render(): TemplateResult { public render(): TemplateResult {
return html` return html`
<style></style> <style></style>
<div class="commitinfo">idp.global v${commitinfo.version}</div>
<div class="logo">idp.global</div>
<div class="navigationGroupLabel">Account Settings</div>
<div
class="navigationOption"
@click=${async () => {
const subrouter = await this.getAccountRouter();
subrouter.pushUrl('');
}}
>
overview
</div>
<div
class="navigationOption"
@click=${async () => {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/logout');
}}
>
logout
</div>
<div
class="navigationOption"
@click=${async () => {
}}
>
manage roles
</div>
<div
class="navigationOption"
@click=${async () => {
}}
>
create an org
</div>
<div class="navigationGroupLabel">Organization Settings</div> <div class="navigationGroupLabel">Organization Settings</div>
<dees-input-dropdown .label=${'choose org:'} <dees-input-dropdown
.label=${'choose org:'}
@selectedOption=${(eventArg: CustomEvent) => { @selectedOption=${(eventArg: CustomEvent) => {
const currentState = states.accountState.getState() const currentState = states.accountState.getState();
states.accountState.dispatchAction(states.setSelectedOrg, currentState.organizations.find(org => org.data.slug === eventArg.detail.payload)); states.accountState.dispatchAction(
states.setSelectedOrg,
currentState.organizations.find((org) => org.data.slug === eventArg.detail.payload)
);
}} }}
></dees-input-dropdown> ></dees-input-dropdown>
${this.options.map(option => { ${this.options.map((option) => {
return html` return html` <div class="navigationOption">${option.text}</div> `;
<div class="navigationOption">
${option.text}
</div>
`;
})} })}
<div class="navigationGroupLabel">Account Settings</div>
`; `;
} }
@@ -125,19 +201,23 @@ export class LeleAccountNavigation extends DeesElement {
option: orgArg.data.name, option: orgArg.data.name,
key: orgArg.data.slug, key: orgArg.data.slug,
payload: orgArg.data.slug, payload: orgArg.data.slug,
} };
} };
states.accountState.select(stateArg => stateArg.organizations).pipe( states.accountState
plugins.deesDomtools.plugins.smartrx.rxjs.ops.map(orgArrayArg => { .select((stateArg) => stateArg.organizations)
return orgArrayArg.map(orgToMenuEntry) .pipe(
plugins.deesDomtools.plugins.smartrx.rxjs.ops.map((orgArrayArg) => {
return orgArrayArg.map(orgToMenuEntry);
}) })
).subscribe(menuEntries => { )
.subscribe((menuEntries) => {
deesInputDropdown.options = menuEntries; deesInputDropdown.options = menuEntries;
}); });
states.accountState.select(stateArg => stateArg.selectedOrg).pipe( states.accountState
plugins.deesDomtools.plugins.smartrx.rxjs.ops.map(orgToMenuEntry) .select((stateArg) => stateArg.selectedOrg)
).subscribe(selectedOrgArg => { .pipe(plugins.deesDomtools.plugins.smartrx.rxjs.ops.map(orgToMenuEntry))
.subscribe((selectedOrgArg) => {
deesInputDropdown.selectedOption = selectedOrgArg; deesInputDropdown.selectedOption = selectedOrgArg;
}) });
} }
} }
+2 -1
View File
@@ -3,7 +3,8 @@ import { css } from '@design.estate/dees-element';
export default css` export default css`
h1 { h1 {
margin-top: 50px; margin-top: 50px;
border-bottom: 1px solid #666; border-bottom: 1px solid;
border-image: radial-gradient(rgba(136, 136, 136, 0.44), rgba(136, 136, 136, 0)) 1 / 1 / 0 stretch;
padding-bottom: 10px; padding-bottom: 10px;
font-weight: 500; font-weight: 500;
} }
+32 -18
View File
@@ -67,24 +67,28 @@ export class BaseView extends DeesElement {
.orgGrid { .orgGrid {
display: grid; display: grid;
grid-gap: 16px; grid-gap: 16px;
grid-template-columns: ${cssManager.cssGridColumns(4, 16)} grid-template-columns: ${cssManager.cssGridColumns(2, 16)};
} }
.org { .org {
padding: 16px; padding: 16px;
border: 1px dotted #666; border-top: 1px solid #444;
border-radius: 3px; background: ${cssManager.bdTheme('#ccc', '#222')};
border-radius: 16px;
} }
.org:hover { .org:hover {
cursor: pointer; cursor: default;
background: ${cssManager.bdTheme('#CCC', '#333')}; background: ${cssManager.bdTheme('#CCC', '#333')};
} }
`, `,
]; ];
public render() { public render() {
return html` <div class="viewHost"></div> `; return html`
<div class="viewHost">
</div> `;
} }
public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) { public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
@@ -147,33 +151,43 @@ export class BaseView extends DeesElement {
subscriptions.push(formSubscription); subscriptions.push(formSubscription);
button.addEventListener('clicked', async () => { button.addEventListener('clicked', async () => {
orgInput.disabled = true; orgInput.disabled = true;
button.text = 'creating org...' button.text = 'creating org...';
button.status = 'pending'; button.status = 'pending';
hint.innerHTML = 'Waiting for creation of the organization...' hint.innerHTML = 'Waiting for creation of the organization...';
await state.accountState.dispatchAction(state.manifestNewOrgName, null); await state.accountState.dispatchAction(state.manifestNewOrgName, null);
hint.innerHTML = `The Organization with name ${state.accountState.getState().organizations[0].data.name} has been created!` hint.innerHTML = `The Organization with name ${
state.accountState.getState().organizations[0].data.name
} has been created!`;
button.text = 'created!'; button.text = 'created!';
button.status = 'success'; button.status = 'success';
const parentElement = (this.getRootNode() as any).host; const parentElement = (this.getRootNode() as any).host;
parentElement.subrouter.pushUrl(`/org/${state.accountState.getState().organizations[0].data.slug}/billing`); parentElement.subrouter.pushUrl(
`/org/${state.accountState.getState().organizations[0].data.slug}/billing`
);
}); });
} else { } else {
render(html` render(
html`
<h1>Select An Organization</h1> <h1>Select An Organization</h1>
<div class="orgGrid"> <div class="orgGrid">
${state.accountState.getState().organizations.map(orgArg => { ${state.accountState.getState().organizations.map((orgArg) => {
return html` return html`
<div class="org" @click=${() => { <div
state.accountState.dispatchAction(state.setSelectedOrg, orgArg) class="org"
@click=${() => {
state.accountState.dispatchAction(state.setSelectedOrg, orgArg);
const parentElement = (this.getRootNode() as any).host; const parentElement = (this.getRootNode() as any).host;
parentElement.subrouter.pushUrl(`/org/${orgArg.data.slug}/billing`) parentElement.subrouter.pushUrl(`/org/${orgArg.data.slug}/billing`);
}}> }}
${orgArg.data.name} >
<dees-icon .iconFA=${"wallet"} style="display: inline-block; transform: translateY(3px); padding-right: 4px;"></dees-icon> ${orgArg.data.name}
</div> </div>
` `;
})} })}
</div> </div>
`, viewHost) `,
viewHost
);
} }
} }
} }
+3 -3
View File
@@ -47,7 +47,7 @@ export class IdpCenterContainer extends DeesElement {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
opacity: 0; opacity: 0;
transition: all 0.1s; transition: all 0.2s;
transition-delay: 0.05s; transition-delay: 0.05s;
transform: translate3d(0px, 8px, 0px); transform: translate3d(0px, 8px, 0px);
pointer-events: none; pointer-events: none;
@@ -126,7 +126,7 @@ export class IdpCenterContainer extends DeesElement {
const done = plugins.smartpromise.defer(); const done = plugins.smartpromise.defer();
requestAnimationFrame(async () => { requestAnimationFrame(async () => {
this.shadowRoot.querySelector('.mainContainer').classList.add('show'); this.shadowRoot.querySelector('.mainContainer').classList.add('show');
await domtoolsInstance.convenience.smartdelay.delayFor(200); await domtoolsInstance.convenience.smartdelay.delayFor(250);
done.resolve(); done.resolve();
}); });
return done.promise; return done.promise;
@@ -138,7 +138,7 @@ export class IdpCenterContainer extends DeesElement {
const done = plugins.smartpromise.defer(); const done = plugins.smartpromise.defer();
requestAnimationFrame(async () => { requestAnimationFrame(async () => {
this.shadowRoot.querySelector('.mainContainer').classList.remove('show'); this.shadowRoot.querySelector('.mainContainer').classList.remove('show');
await domtoolsInstance.convenience.smartdelay.delayFor(200); await domtoolsInstance.convenience.smartdelay.delayFor(250);
done.resolve(); done.resolve();
}); });
return done.promise; return done.promise;
+6 -1
View File
@@ -111,7 +111,12 @@ export class IdpRegistrationPrompt extends DeesElement {
} }
public async firstUpdated() { public async firstUpdated() {
const domtoolsInstance = await this.domtoolsPromise; await this.domtoolsPromise;
const idpState = await IdpState.getSingletonInstance();
const loggedIn = await idpState.idpClient.determineLoginStatus();
if (loggedIn) {
idpState.domtools.router.pushUrl('/');
}
const loginForm: DeesForm = this.shadowRoot.querySelector('#loginForm'); const loginForm: DeesForm = this.shadowRoot.querySelector('#loginForm');
const loginPasswordInput: DeesInputText = loginForm.querySelector('#loginPasswordInput'); const loginPasswordInput: DeesInputText = loginForm.querySelector('#loginPasswordInput');
const loginSubmitButton: DeesFormSubmit = loginForm.querySelector('#loginSubmitButton'); const loginSubmitButton: DeesFormSubmit = loginForm.querySelector('#loginSubmitButton');
+72 -39
View File
@@ -9,6 +9,7 @@ import {
cssManager, cssManager,
unsafeCSS, unsafeCSS,
css, css,
resolveExec,
type TemplateResult, type TemplateResult,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import type { IdpViewcontainer } from '../views/viewcontainer.js'; import type { IdpViewcontainer } from '../views/viewcontainer.js';
@@ -34,27 +35,20 @@ export class IdpWelcome extends DeesElement {
display: none; display: none;
} }
h1 { .maincontainer {
font-family: 'Cal Sans'; padding: 0px 16px;
}
.greeting {
text-align: center; text-align: center;
font-size: 24px; font-size: 16px;
margin: 0px auto; font-weight: 600;
padding: 24px 24px 0px 24px;
width: 500px;
letter-spacing:0.0125em;
}
.textbox {
margin: 24px auto; margin: 24px auto;
width: 500px;
background: #111111;
border-radius: 16px;
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#222222')};
padding: 24px;
} }
.textbox dees-button { dees-button {
margin-top: 16px; margin-top: 16px;
margin-bottom: 16px;
} }
`, `,
]; ];
@@ -62,31 +56,70 @@ export class IdpWelcome extends DeesElement {
public render(): TemplateResult { public render(): TemplateResult {
return html` return html`
<style></style> <style></style>
<h1>idp.global</h1> <idp-centercontainer>
<div class="maincontainer">
<div class="textbox"> ${resolveExec(async () => {
Do you want to sign in or register?
<dees-button @click=${async () => {
const idpState = await IdpState.getSingletonInstance(); const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/login'); await idpState.idpClient.determineLoginStatus();
}}>Sign In</dees-button> const data = await idpState.idpClient.whoIs().catch();
<dees-button @click=${async () => { if (data?.user) {
return html`
<div class="greeting">Hello ${data.user.data.name}!</div>
<dees-button
@click=${async () => {
const idpState = await IdpState.getSingletonInstance(); const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/register'); idpState.domtools.router.pushUrl('/account');
}}>Register</dees-button> }}
</div> >Manage your account</dees-button
>
<div class="textbox"> <dees-button
Do you want to use idp.global for your app? @click=${async () => {
<dees-button @click=${() => {}}>Open Developer Dashboard</dees-button> const idpState = await IdpState.getSingletonInstance();
</div> idpState.domtools.router.pushUrl('/logout');
}}
<div class="textbox"> >Logout</dees-button
idp.global is a Open Source identity provider for the world wide web. You can get the code if you want to improve it. >
<dees-button @click=${() => {
window.open('https://code.foss.global/idp.global/idp.global', '_blank');
}}>Get the code</dees-button>
</div>
`; `;
} }
return html`
Do you want to sign in or register?
<dees-button
@click=${async () => {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/login');
}}
>Sign In</dees-button
>
<dees-button
@click=${async () => {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/register');
}}
>Register</dees-button
>
`;
})}
<dees-button @click=${() => {}}>Open Developer Dashboard</dees-button>
<dees-button
@click=${() => {
window.open('https://code.foss.global/idp.global/idp.global', '_blank');
}}
>Get the Source Code</dees-button
>
</div>
</idp-centercontainer>
`;
}
public async show() {
await this.updateComplete;
const centerContainer = this.shadowRoot.querySelector('idp-centercontainer');
await centerContainer.show();
}
public async hide() {
await this.updateComplete;
const centerContainer = this.shadowRoot.querySelector('idp-centercontainer');
await centerContainer.hide();
}
} }
+9 -1
View File
@@ -19,7 +19,7 @@ export class IdpState {
public idpClient = new plugins.idpClient.IdpClient(this.receptionUrl); public idpClient = new plugins.idpClient.IdpClient(this.receptionUrl);
public domtools: domtools.DomTools; public domtools: domtools.DomTools;
public mainStatePart: plugins.deesDomtools.plugins.smartstate.StatePart<'main', { public mainStatePart: plugins.deesDomtools.plugins.smartstate.StatePart<'main', {
view: 'welcome' | 'login' | 'register' | 'finishregistration' | 'account'; view: 'welcome' | 'login' | 'register' | 'finishregistration' | 'account' | 'logout';
}> }>
public async init() { public async init() {
@@ -44,6 +44,14 @@ export class IdpState {
}) })
}); });
this.domtools.router.on('/logout', async () => {
await this.idpClient.logout();
await this.mainStatePart.setState({
...this.mainStatePart.getState(),
view: 'logout',
})
});
this.domtools.router.on('/register', async () => { this.domtools.router.on('/register', async () => {
await this.mainStatePart.setState({ await this.mainStatePart.setState({
...this.mainStatePart.getState(), ...this.mainStatePart.getState(),
+4
View File
@@ -59,6 +59,10 @@ export class IdpViewcontainer extends DeesElement {
throw new Error('View container not found in the rendered DOM.'); throw new Error('View container not found in the rendered DOM.');
} }
if (!this.currentElement) {
this.currentElement = viewContainer.children[0] as any;
}
// check if current element already is instance of viewElement // check if current element already is instance of viewElement
if (this.currentElement instanceof viewElement) { if (this.currentElement instanceof viewElement) {
return; return;