diff --git a/changelog.md b/changelog.md index 704360f..161a125 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 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. diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index d69f5ea..2250aeb 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@idp.global/idp.global', - version: '1.3.1', + version: '1.4.0', description: 'An identity provider software managing user authentications, registrations, and sessions.' } diff --git a/ts/plugins.ts b/ts/plugins.ts index 2a49640..a8258d9 100644 --- a/ts/plugins.ts +++ b/ts/plugins.ts @@ -3,8 +3,8 @@ import * as path from 'path'; export { path }; // Project scope -import * as lointReception from '../dist_ts_interfaces/index.js'; -export { lointReception }; +import * as idpInterfaces from '../dist_ts_interfaces/index.js'; +export { idpInterfaces }; // @api.global scope import * as typedserver from '@api.global/typedserver'; diff --git a/ts/reception/classes.billingplan.ts b/ts/reception/classes.billingplan.ts index ebed8b2..ee1d5e3 100644 --- a/ts/reception/classes.billingplan.ts +++ b/ts/reception/classes.billingplan.ts @@ -8,7 +8,7 @@ import { User } from './classes.user.js'; @plugins.smartdata.Manager() export class BillingPlan extends plugins.smartdata.SmartDataDbDoc< BillingPlan, - plugins.lointReception.data.IBillingPlan, + plugins.idpInterfaces.data.IBillingPlan, BillingPlanManager > { // STATIC @@ -20,7 +20,7 @@ export class BillingPlan extends plugins.smartdata.SmartDataDbDoc< public id: string; @plugins.smartdata.svDb() - public data: plugins.lointReception.data.IBillingPlan['data'] = { + public data: plugins.idpInterfaces.data.IBillingPlan['data'] = { type: null, organizationId: null, lastProcessed: null, diff --git a/ts/reception/classes.billingplanmanager.ts b/ts/reception/classes.billingplanmanager.ts index a530cd4..094869f 100644 --- a/ts/reception/classes.billingplanmanager.ts +++ b/ts/reception/classes.billingplanmanager.ts @@ -14,7 +14,7 @@ export class BillingPlanManager { constructor(receptionRefArg: Reception) { this.receptionRef = receptionRefArg; this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); - this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('updatePaymentMethod', async reqDataArg => { + this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('updatePaymentMethod', async reqDataArg => { const user = await this.receptionRef.userManager.getUserByJwt(reqDataArg.jwtString); const organization = await this.receptionRef.organizationmanager.COrganization.getInstance({ id: reqDataArg.orgId, diff --git a/ts/reception/classes.jwt.ts b/ts/reception/classes.jwt.ts index 63d7557..2c532cf 100644 --- a/ts/reception/classes.jwt.ts +++ b/ts/reception/classes.jwt.ts @@ -6,7 +6,7 @@ import { JwtManager } from './classes.jwtmanager.js'; * Both need to be unique and both can be changed. */ @plugins.smartdata.Manager() -export class Jwt extends plugins.smartdata.SmartDataDbDoc { +export class Jwt extends plugins.smartdata.SmartDataDbDoc { // STATIC public static async createJwtForRefreshToken( jwtManagerInstance: JwtManager, @@ -48,7 +48,7 @@ export class Jwt extends plugins.smartdata.SmartDataDbDoc( + this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'refreshJwt', async (requestArg) => { @@ -34,7 +34,7 @@ export class JwtManager { ) ); this.typedrouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'getPublicKeyForValidation', async (requestArg) => { // TODO control backend token @@ -46,7 +46,7 @@ export class JwtManager { ); this.typedrouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'pushOrGetJwtIdBlocklist', async (requestArg) => { // TODO control backend token @@ -60,7 +60,7 @@ export class JwtManager { public async pushPublicKeyToClients() { const targetConnections = - await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag( + await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag( 'lole-reception', { backendToken: '', @@ -68,7 +68,7 @@ export class JwtManager { ); for (const targetConnection of targetConnections) { const pushPublicKeyTr = - this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest( + this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest( 'pushPublicKeyForValidation', targetConnection ); @@ -80,7 +80,7 @@ export class JwtManager { public async pushBlockedJwtIdListToClients() { const targetConnections = - await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag( + await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag( 'lole-reception', { backendToken: '', @@ -88,7 +88,7 @@ export class JwtManager { ); for (const targetConnection of targetConnections) { const pushPublicKeyTr = - this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest( + this.receptionRef.options.websiteServer.typedserver.typedsocket.createTypedRequest( 'pushOrGetJwtIdBlocklist', targetConnection ); @@ -121,7 +121,7 @@ export class JwtManager { } public async verifyJWTAndGetData(jwtArg: string): Promise { - 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({ id: jwtData.id, }); diff --git a/ts/reception/classes.loginsession.ts b/ts/reception/classes.loginsession.ts index 4c58851..41f298d 100644 --- a/ts/reception/classes.loginsession.ts +++ b/ts/reception/classes.loginsession.ts @@ -8,7 +8,7 @@ import { User } from './classes.user.js'; @plugins.smartdata.Manager() export class LoginSession extends plugins.smartdata.SmartDataDbDoc< LoginSession, - plugins.lointReception.data.ILoginSession, + plugins.idpInterfaces.data.ILoginSession, LoginSessionManager > { // ====== @@ -55,7 +55,7 @@ export class LoginSession extends plugins.smartdata.SmartDataDbDoc< public id: string; @plugins.smartdata.svDb() - public data: plugins.lointReception.data.ILoginSession['data'] = { + public data: plugins.idpInterfaces.data.ILoginSession['data'] = { userId: null, validUntil: Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ weeks: 1 }), invalidated: false, diff --git a/ts/reception/classes.loginsessionmanager.ts b/ts/reception/classes.loginsessionmanager.ts index 588b8ad..79f3bac 100644 --- a/ts/reception/classes.loginsessionmanager.ts +++ b/ts/reception/classes.loginsessionmanager.ts @@ -26,7 +26,7 @@ export class LoginSessionManager { this.receptionRef = receptionRefArg; this.receptionRef.typedrouter.addTypedRouter(this.typedRouter); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'loginWithEmailOrUsernameAndPassword', async (requestData) => { let user = await this.receptionRef.userManager.CUser.getInstance({ @@ -79,7 +79,7 @@ export class LoginSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'loginWithEmail', async (requestDataArg) => { logger.log('info', `loginWithEmail requested for: ${requestDataArg.email}`); @@ -121,7 +121,7 @@ export class LoginSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'loginWithEmailAfterEmailTokenAquired', async (requestArg) => { const tokenObject = this.emailTokenMap.findSync((itemArg) => { @@ -145,7 +145,7 @@ export class LoginSessionManager { ) ); - this.typedRouter.addTypedHandler( + this.typedRouter.addTypedHandler( new plugins.typedrequest.TypedHandler('logout', async (requestDataArg) => { const loginSession = await this.CLoginSession.getLoginSessionByRefreshToken(requestDataArg.refreshToken); await loginSession.invalidate(); @@ -153,7 +153,7 @@ export class LoginSessionManager { }) ); - this.typedRouter.addTypedHandler( + this.typedRouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'exchangeRefreshTokenAndTransferToken', async (requestDataArg) => { @@ -189,7 +189,7 @@ export class LoginSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'resetPassword', async (requestDataArg) => { const emailOfPasswordToReset = requestDataArg.email; @@ -227,7 +227,7 @@ export class LoginSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'setNewPassword', async (requestData) => { return { @@ -241,7 +241,7 @@ export class LoginSessionManager { * returns a device id by simply returning a uuid4 */ this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler('obtainDeviceId', async (reqData) => { + new plugins.typedrequest.TypedHandler('obtainDeviceId', async (reqData) => { reqData; return { deviceId: { @@ -252,7 +252,7 @@ export class LoginSessionManager { ) this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler('attachDeviceId', async (reqData) => { + new plugins.typedrequest.TypedHandler('attachDeviceId', async (reqData) => { // TODO: Blocked by proper JWT handling reqData.jwt; return { diff --git a/ts/reception/classes.organization.ts b/ts/reception/classes.organization.ts index 65fb0e8..5b1155b 100644 --- a/ts/reception/classes.organization.ts +++ b/ts/reception/classes.organization.ts @@ -5,7 +5,7 @@ import { User } from './classes.user.js'; @plugins.smartdata.Manager() export class Organization extends plugins.smartdata.SmartDataDbDoc< Organization, - plugins.lointReception.data.IOrganization, + plugins.idpInterfaces.data.IOrganization, OrganizationManager > { public static async createNewOrganizationForUser( @@ -28,10 +28,10 @@ export class Organization extends plugins.smartdata.SmartDataDbDoc< // INSTANCE @plugins.smartdata.unI() - id: plugins.lointReception.data.IOrganization['id']; + id: plugins.idpInterfaces.data.IOrganization['id']; @plugins.smartdata.svDb() - data: plugins.lointReception.data.IOrganization['data']; + data: plugins.idpInterfaces.data.IOrganization['data']; public async checkIfUserIsAdmin(userArg: User) { const role = await this.manager.receptionRef.roleManager.getRoleForUserAndOrg(userArg, this); diff --git a/ts/reception/classes.organizationmanager.ts b/ts/reception/classes.organizationmanager.ts index 7baaf82..5f857bc 100644 --- a/ts/reception/classes.organizationmanager.ts +++ b/ts/reception/classes.organizationmanager.ts @@ -17,7 +17,7 @@ export class OrganizationManager { this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); this.typedrouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'createOrganization', async (requestArg) => { const nameIsAvailable = async () => { @@ -64,7 +64,7 @@ export class OrganizationManager { ) ); this.typedrouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'getOrganizationById', async (requestArg) => { const verifiedJwt = await this.receptionRef.jwtManager.verifyJWTAndGetData( diff --git a/ts/reception/classes.registrationsession.ts b/ts/reception/classes.registrationsession.ts index ca6cba6..6b0f289 100644 --- a/ts/reception/classes.registrationsession.ts +++ b/ts/reception/classes.registrationsession.ts @@ -68,7 +68,7 @@ export class RegistrationSession { 'announced'; public collectedData: { - userData: plugins.lointReception.data.IUser['data']; + userData: plugins.idpInterfaces.data.IUser['data']; } = { userData: { username: null, diff --git a/ts/reception/classes.registrationsessionmanager.ts b/ts/reception/classes.registrationsessionmanager.ts index 950d5b5..4d36b9b 100644 --- a/ts/reception/classes.registrationsessionmanager.ts +++ b/ts/reception/classes.registrationsessionmanager.ts @@ -14,7 +14,7 @@ export class RegistrationSessionManager { this.receptionRef.typedrouter.addTypedRouter(this.typedRouter); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'firstRegistrationRequest', async (requestData) => { // check for exiting User @@ -60,7 +60,7 @@ export class RegistrationSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'afterRegistrationEmailClicked', async (requestData) => { console.log(requestData); @@ -83,7 +83,7 @@ export class RegistrationSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'setDataForRegistration', async (requestData) => { const registrationSession = await this.registrationSessions.find(async (itemArg) => @@ -111,7 +111,7 @@ export class RegistrationSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'mobileVerificationForRegistration', async (requestData) => { const registrationSession = await this.registrationSessions.find(async (itemArg) => @@ -157,7 +157,7 @@ export class RegistrationSessionManager { ); this.typedRouter.addTypedHandler( - new plugins.typedrequest.TypedHandler( + new plugins.typedrequest.TypedHandler( 'finishRegistration', async (requestData) => { const registrationSession = await this.registrationSessions.find(async (itemArg) => diff --git a/ts/reception/classes.role.ts b/ts/reception/classes.role.ts index b501143..61eb902 100644 --- a/ts/reception/classes.role.ts +++ b/ts/reception/classes.role.ts @@ -3,12 +3,12 @@ import * as plugins from '../plugins.js'; @plugins.smartdata.Manager() export class Role extends plugins.smartdata.SmartDataDbDoc< Role, - plugins.lointReception.data.IRole + plugins.idpInterfaces.data.IRole > { @plugins.smartdata.unI() id: string; @plugins.smartdata.svDb() - data: plugins.lointReception.data.IRole['data']; + data: plugins.idpInterfaces.data.IRole['data']; } \ No newline at end of file diff --git a/ts/reception/classes.rolemanager.ts b/ts/reception/classes.rolemanager.ts index 1dbec12..482f6ec 100644 --- a/ts/reception/classes.rolemanager.ts +++ b/ts/reception/classes.rolemanager.ts @@ -19,7 +19,7 @@ export class RoleManager { action: 'create' | 'change' | 'delete'; userId: string; organizationId: string; - role: plugins.lointReception.data.IRole['data']['role']; + role: plugins.idpInterfaces.data.IRole['data']['role']; }) { let returnRole: Role; switch (optionsArg.action) { diff --git a/ts/reception/classes.user.ts b/ts/reception/classes.user.ts index 1f82a98..9b099f7 100644 --- a/ts/reception/classes.user.ts +++ b/ts/reception/classes.user.ts @@ -8,11 +8,11 @@ import { UserManager } from './classes.usermanager.js'; @plugins.smartdata.Manager() export class User extends plugins.smartdata.SmartDataDbDoc< User, - plugins.lointReception.data.IUser + plugins.idpInterfaces.data.IUser > { // STATIC public static async createNewUserForUserData( - userDataArg: plugins.lointReception.data.IUser['data'] + userDataArg: plugins.idpInterfaces.data.IUser['data'] ): Promise { const newUser = new User(); newUser.id = plugins.smartunique.shortId(); @@ -40,7 +40,7 @@ export class User extends plugins.smartdata.SmartDataDbDoc< id: string; @plugins.smartdata.svDb() - public data: plugins.lointReception.data.IUser['data']; + public data: plugins.idpInterfaces.data.IUser['data']; constructor() { super(); diff --git a/ts/reception/classes.usermanager.ts b/ts/reception/classes.usermanager.ts index 8867467..0ae5943 100644 --- a/ts/reception/classes.usermanager.ts +++ b/ts/reception/classes.usermanager.ts @@ -19,7 +19,7 @@ export class UserManager { constructor(receptionRefArg: Reception) { this.receptionRef = receptionRefArg; this.receptionRef.typedrouter.addTypedRouter(this.typedrouter); - this.typedrouter.addTypedHandler( + this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler('getRolesAndOrganizationsForUserId', async reqArg => { console.log('user manager: getting roles and orgs'); const user = await this.getUserByJwtValidation(reqArg.jwt); @@ -33,6 +33,29 @@ export class UserManager { } }) ) + + this.typedrouter.addTypedHandler( + 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" */ 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({ id: jwtDataArg.data.userId }); diff --git a/ts_idpclient/classes.idpclient.ts b/ts_idpclient/classes.idpclient.ts index ac8c001..d23643c 100644 --- a/ts_idpclient/classes.idpclient.ts +++ b/ts_idpclient/classes.idpclient.ts @@ -4,19 +4,19 @@ import * as plugins from './plugins.js'; export class IdpClient { // INSTANCE PRIVATE private helpers = { - async extractDataFromJwtString(jwtString: string): Promise { + async extractDataFromJwtString(jwtString: string): Promise { return plugins.webjwt.getDataFromJwtString(jwtString); }, }; // INSTANCE PUBLIC - public appData: plugins.lointReception.data.IApp; + public appData: plugins.idpInterfaces.data.IApp; public rolesReplaySubject = new plugins.smartrx.rxjs.ReplaySubject(1); public organizationsReplaySubject = new plugins.smartrx.rxjs.ReplaySubject(1); public parsedReceptionUrl: plugins.smarturl.Smarturl; - constructor(receptionBaseUrlArg: string, appDataArg?: plugins.lointReception.data.IApp) { + constructor(receptionBaseUrlArg: string, appDataArg?: plugins.idpInterfaces.data.IApp) { if (receptionBaseUrlArg.endsWith('/')) { receptionBaseUrlArg = receptionBaseUrlArg.slice(0, -1); } @@ -78,7 +78,7 @@ export class IdpClient { public typedrouter = new plugins.typedrequest.TypedRouter(); public statusObservable = - new plugins.smartrx.rxjs.Subject(); + new plugins.smartrx.rxjs.Subject(); public ssoStore = new plugins.webstore.WebStore({ storeName: 'idpglobalStore', @@ -92,7 +92,7 @@ export class IdpClient { public async getJwt(): Promise { return await this.ssoStore.get('idpJwt'); } - public async getJwtData(): Promise { + public async getJwtData(): Promise { return this.helpers.extractDataFromJwtString(await this.getJwt()); } @@ -121,13 +121,13 @@ export class IdpClient { } public async refreshJwt(refreshTokenArg?: string): Promise { - let extractedJwt: plugins.lointReception.data.IJwt; + let extractedJwt: plugins.idpInterfaces.data.IJwt; if (!refreshTokenArg) { extractedJwt = await this.helpers.extractDataFromJwtString(await this.getJwt()); } const refreshJwtReq = - new plugins.typedrequest.TypedRequest( + new plugins.typedrequest.TypedRequest( this.parsedReceptionUrl.toString(), 'refreshJwt' ); @@ -146,11 +146,11 @@ export class IdpClient { /** * can be used to switch between pages */ - public async getTransferToken(appDataArg?: plugins.lointReception.data.IApp): Promise { + public async getTransferToken(appDataArg?: plugins.idpInterfaces.data.IApp): Promise { const jwt = await this.performJwtHousekeeping(); const extractedJwt = await this.helpers.extractDataFromJwtString(jwt); const getTransferToken = - new plugins.typedrequest.TypedRequest( + new plugins.typedrequest.TypedRequest( this.parsedReceptionUrl.toString(), 'exchangeRefreshTokenAndTransferToken' ); @@ -188,7 +188,7 @@ export class IdpClient { const transferToken = url.searchParams['transfertoken']; if (transferToken) { const getTransferToken = - new plugins.typedrequest.TypedRequest( + new plugins.typedrequest.TypedRequest( this.parsedReceptionUrl.toString(), '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 * @returns */ @@ -256,22 +257,17 @@ export class IdpClient { * logs out the current user */ public async logout() { - const urlInstance = plugins.smarturl.Smarturl.createFromUrl('https://sso.workspace.global/', { - searchParams: { - appdata: plugins.smartjson.stringifyBase64(this.appData), - action: 'logout', - }, - }); - if (!globalThis.location.href.startsWith('https://sso.workspace.global/')) { + const idpLogoutUrl = this.parsedReceptionUrl.clone().set('path', '/logout'); + if (!globalThis.location.href.startsWith(idpLogoutUrl.origin)) { // we are somewhere in an app await this.deleteJwt(); - globalThis.location.href = urlInstance.toString(); + globalThis.location.href = idpLogoutUrl.toString(); } else { // we are in the sso page await this.enableTypedSocket(); console.log(`logging out against ${this.parsedReceptionUrl.toString()}`); const logoutTr = - this.typedsocket.createTypedRequest( + this.typedsocket.createTypedRequest( 'logout' ); await logoutTr.fire({ @@ -285,6 +281,9 @@ export class IdpClient { } else { 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; const validateOrg = - this.typedsocket.createTypedRequest( + this.typedsocket.createTypedRequest( 'createOrganization' ); const response = await validateOrg.fire({ @@ -336,7 +335,7 @@ export class IdpClient { console.log('idpclient: getting roles and orgs...'); await this.typedsocketDeferred.promise; const rolesAndOrganizationsForUserId = - this.typedsocket.createTypedRequest( + this.typedsocket.createTypedRequest( 'getRolesAndOrganizationsForUserId' ); const response = await rolesAndOrganizationsForUserId.fire({ @@ -352,7 +351,7 @@ export class IdpClient { public async updatePaddleCheckoutId(orgIdArg: string, checkoutIdArg: string) { await this.typedsocketDeferred.promise; const updateBillingPlan = - this.typedsocket.createTypedRequest( + this.typedsocket.createTypedRequest( 'updatePaymentMethod' ); const response = await updateBillingPlan.fire({ @@ -364,4 +363,16 @@ export class IdpClient { }); return response; } + + public async whoIs() { + await this.typedsocketDeferred.promise; + const whoIs = + this.typedsocket.createTypedRequest( + 'whoIs' + ); + const response = await whoIs.fire({ + jwt: await this.getJwt(), + }); + return response; + } } diff --git a/ts_idpclient/classes.idprequests.ts b/ts_idpclient/classes.idprequests.ts index b8857d1..db111ca 100644 --- a/ts_idpclient/classes.idprequests.ts +++ b/ts_idpclient/classes.idprequests.ts @@ -11,21 +11,21 @@ export class IdpRequests { } public get afterRegistrationEmailClicked () { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'afterRegistrationEmailClicked' ); } public get setData() { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'setDataForRegistration' ); } public get mobileNumberVerification () { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'mobileVerificationForRegistration' ); @@ -33,28 +33,28 @@ export class IdpRequests { public get finishRegistration() { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'finishRegistration' ); } public get loginWithUserNameAndPassword () { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'loginWithEmailOrUsernameAndPassword' ); } public get obtainJwt () { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'refreshJwt' ); } public get obtainOneTimeToken () { - return new plugins.typedrequest.TypedRequest( + return new plugins.typedrequest.TypedRequest( this.idpClientArg.parsedReceptionUrl.toString(), 'exchangeRefreshTokenAndTransferToken' ); diff --git a/ts_idpclient/plugins.ts b/ts_idpclient/plugins.ts index eabc0e8..3f60f70 100644 --- a/ts_idpclient/plugins.ts +++ b/ts_idpclient/plugins.ts @@ -1,7 +1,7 @@ // 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 import * as typedrequest from '@api.global/typedrequest'; diff --git a/ts_interfaces/request/loint-reception.user.ts b/ts_interfaces/request/loint-reception.user.ts index eb49fea..d721ce1 100644 --- a/ts_interfaces/request/loint-reception.user.ts +++ b/ts_interfaces/request/loint-reception.user.ts @@ -74,3 +74,13 @@ export interface IReq_GetRolesAndOrganizationsForUserId organizations: data.IOrganization[]; }; } + +export interface IReq_WhoIs { + method: 'whoIs'; + request: { + jwt: string; + }; + response: { + user: data.IUser; + }; +} diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index d69f5ea..2250aeb 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@idp.global/idp.global', - version: '1.3.1', + version: '1.4.0', description: 'An identity provider software managing user authentications, registrations, and sessions.' } diff --git a/ts_web/elements/account/navigation.ts b/ts_web/elements/account/navigation.ts index 6188f41..2b774e7 100644 --- a/ts_web/elements/account/navigation.ts +++ b/ts_web/elements/account/navigation.ts @@ -7,11 +7,14 @@ import { unsafeCSS, css, type TemplateResult, - subscribe + subscribe, } from '@design.estate/dees-element'; import * as plugins from '../../plugins.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 { interface HTMLElementTagNameMap { @@ -22,22 +25,22 @@ declare global { @customElement('lele-accountnavigation') export class LeleAccountNavigation extends DeesElement { @property() - public options: {text: string; id: string}[] = [ + public options: { text: string; id: string }[] = [ { id: '1', - text: 'Properties' + text: 'Properties', }, { id: '2', - text: 'Users' + text: 'Users', }, { id: '3', - text: 'Activity' + text: 'Activity', }, { id: '4', - text: 'Billing & Subscription' + text: 'Billing & Subscription', }, ]; @@ -60,6 +63,19 @@ export class LeleAccountNavigation extends DeesElement { display: none; } + .commitinfo { + text-align: center; + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + font-size: 12px; + padding: 8px; + background: ${cssManager.bdTheme('#eeeeeb', '#181818')}; + border-top: ${cssManager.bdTheme('1px solid #ccc', '1px solid #333')}; + color: ${cssManager.bdTheme('#666', '#ccc')}; + } + .navigationGroupLabel { width: min-content; white-space: nowrap; @@ -97,21 +113,46 @@ export class LeleAccountNavigation extends DeesElement { public render(): TemplateResult { return html` +
idp.global v${commitinfo.version}
+ + + + - { - const currentState = states.accountState.getState() - states.accountState.dispatchAction(states.setSelectedOrg, currentState.organizations.find(org => org.data.slug === eventArg.detail.payload)); + const currentState = states.accountState.getState(); + states.accountState.dispatchAction( + states.setSelectedOrg, + currentState.organizations.find((org) => org.data.slug === eventArg.detail.payload) + ); }} > - ${this.options.map(option => { - return html` - - `; + ${this.options.map((option) => { + return html` `; })} - `; } @@ -125,19 +166,23 @@ export class LeleAccountNavigation extends DeesElement { option: orgArg.data.name, key: orgArg.data.slug, payload: orgArg.data.slug, - } - } - states.accountState.select(stateArg => stateArg.organizations).pipe( - plugins.deesDomtools.plugins.smartrx.rxjs.ops.map(orgArrayArg => { - return orgArrayArg.map(orgToMenuEntry) - }) - ).subscribe(menuEntries => { - deesInputDropdown.options = menuEntries; - }); - states.accountState.select(stateArg => stateArg.selectedOrg).pipe( - plugins.deesDomtools.plugins.smartrx.rxjs.ops.map(orgToMenuEntry) - ).subscribe(selectedOrgArg => { - deesInputDropdown.selectedOption = selectedOrgArg; - }) + }; + }; + states.accountState + .select((stateArg) => stateArg.organizations) + .pipe( + plugins.deesDomtools.plugins.smartrx.rxjs.ops.map((orgArrayArg) => { + return orgArrayArg.map(orgToMenuEntry); + }) + ) + .subscribe((menuEntries) => { + deesInputDropdown.options = menuEntries; + }); + states.accountState + .select((stateArg) => stateArg.selectedOrg) + .pipe(plugins.deesDomtools.plugins.smartrx.rxjs.ops.map(orgToMenuEntry)) + .subscribe((selectedOrgArg) => { + deesInputDropdown.selectedOption = selectedOrgArg; + }); } } diff --git a/ts_web/elements/idp-welcome.ts b/ts_web/elements/idp-welcome.ts index 3571765..99745f4 100644 --- a/ts_web/elements/idp-welcome.ts +++ b/ts_web/elements/idp-welcome.ts @@ -9,6 +9,7 @@ import { cssManager, unsafeCSS, css, + resolveExec, type TemplateResult, } from '@design.estate/dees-element'; import type { IdpViewcontainer } from '../views/viewcontainer.js'; @@ -41,7 +42,7 @@ export class IdpWelcome extends DeesElement { margin: 0px auto; padding: 24px 24px 0px 24px; width: 500px; - letter-spacing:0.0125em; + letter-spacing: 0.0125em; } .textbox { @@ -56,24 +57,56 @@ export class IdpWelcome extends DeesElement { .textbox dees-button { margin-top: 16px; } - `, + `, ]; public render(): TemplateResult { return html`

idp.global

- +
- Do you want to sign in or register? - { + ${resolveExec(async () => { const idpState = await IdpState.getSingletonInstance(); - idpState.domtools.router.pushUrl('/login'); - }}>Sign In - { - const idpState = await IdpState.getSingletonInstance(); - idpState.domtools.router.pushUrl('/register'); - }}>Register + await idpState.idpClient.determineLoginStatus(); + const data = await idpState.idpClient.whoIs().catch(); + if (data?.user) { + return html` + Hello ${data.user.data.name}! + { + const idpState = await IdpState.getSingletonInstance(); + idpState.domtools.router.pushUrl('/account'); + }} + >Manage your account + { + const idpState = await IdpState.getSingletonInstance(); + idpState.domtools.router.pushUrl('/logout'); + }} + >Logout + ` + } + return html` + Do you want to sign in or register? + { + const idpState = await IdpState.getSingletonInstance(); + idpState.domtools.router.pushUrl('/login'); + }} + >Sign In + { + const idpState = await IdpState.getSingletonInstance(); + idpState.domtools.router.pushUrl('/register'); + }} + >Register + `; + })}
@@ -82,10 +115,14 @@ export class IdpWelcome extends DeesElement {
- idp.global is a Open Source identity provider for the world wide web. You can get the code if you want to improve it. - { - window.open('https://code.foss.global/idp.global/idp.global', '_blank'); - }}>Get the code + idp.global is a Open Source identity provider for the world wide web. You can get the code + if you want to improve it. + { + window.open('https://code.foss.global/idp.global/idp.global', '_blank'); + }} + >Get the code
`; } diff --git a/ts_web/states/idp.state.ts b/ts_web/states/idp.state.ts index 6ff3e25..061b899 100644 --- a/ts_web/states/idp.state.ts +++ b/ts_web/states/idp.state.ts @@ -19,7 +19,7 @@ export class IdpState { public idpClient = new plugins.idpClient.IdpClient(this.receptionUrl); public domtools: domtools.DomTools; public mainStatePart: plugins.deesDomtools.plugins.smartstate.StatePart<'main', { - view: 'welcome' | 'login' | 'register' | 'finishregistration' | 'account'; + view: 'welcome' | 'login' | 'register' | 'finishregistration' | 'account' | 'logout'; }> 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 () => { await this.mainStatePart.setState({ ...this.mainStatePart.getState(),