4 Commits

Author SHA1 Message Date
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
27 changed files with 274 additions and 128 deletions
+12
View File
@@ -1,5 +1,17 @@
# 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.
- 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)
Implement account and organization management features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@idp.global/idp.global",
"version": "1.3.0",
"version": "1.4.0",
"description": "An identity provider software managing user authentications, registrations, and sessions.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
+1 -1
View File
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@idp.global/idp.global',
version: '1.3.0',
version: '1.4.0',
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 };
// 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';
+2 -2
View File
@@ -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,
+1 -1
View File
@@ -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<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 organization = await this.receptionRef.organizationmanager.COrganization.getInstance({
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.
*/
@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
public static async createJwtForRefreshToken(
jwtManagerInstance: JwtManager,
@@ -48,7 +48,7 @@ export class Jwt extends plugins.smartdata.SmartDataDbDoc<Jwt, plugins.lointRece
id: jwt.id,
blocked: null,
data: jwt.data,
} as plugins.lointReception.data.IJwt);
} as plugins.idpInterfaces.data.IJwt);
return jwtString;
}
@@ -60,7 +60,7 @@ export class Jwt extends plugins.smartdata.SmartDataDbDoc<Jwt, plugins.lointRece
public blocked: boolean = false;
@plugins.smartdata.svDb()
public data: plugins.lointReception.data.IJwt['data'];
public data: plugins.idpInterfaces.data.IJwt['data'];
public async block() {
this.blocked = true;
+8 -8
View File
@@ -21,7 +21,7 @@ export class JwtManager {
constructor(receptionRefArg: Reception) {
this.receptionRef = receptionRefArg;
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(
'refreshJwt',
async (requestArg) => {
@@ -34,7 +34,7 @@ export class JwtManager {
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_GetPublicKeyForValidation>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_GetPublicKeyForValidation>(
'getPublicKeyForValidation',
async (requestArg) => {
// TODO control backend token
@@ -46,7 +46,7 @@ export class JwtManager {
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_PushOrGetJwtIdBlocklist>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_PushOrGetJwtIdBlocklist>(
'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<plugins.lointReception.tags.ITag_LolePubapi>(
await this.receptionRef.options.websiteServer.typedserver.typedsocket.findAllTargetConnectionsByTag<plugins.idpInterfaces.tags.ITag_LolePubapi>(
'lole-reception',
{
backendToken: '',
@@ -68,7 +68,7 @@ export class JwtManager {
);
for (const targetConnection of targetConnections) {
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',
targetConnection
);
@@ -80,7 +80,7 @@ export class JwtManager {
public async pushBlockedJwtIdListToClients() {
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',
{
backendToken: '',
@@ -88,7 +88,7 @@ export class JwtManager {
);
for (const targetConnection of targetConnections) {
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',
targetConnection
);
@@ -121,7 +121,7 @@ export class JwtManager {
}
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({
id: jwtData.id,
});
+2 -2
View File
@@ -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,
+9 -9
View File
@@ -26,7 +26,7 @@ export class LoginSessionManager {
this.receptionRef = receptionRefArg;
this.receptionRef.typedrouter.addTypedRouter(this.typedRouter);
this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_LoginWithEmailOrUsernameAndPassword>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_LoginWithEmailOrUsernameAndPassword>(
'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<plugins.lointReception.request.IReq_LoginWithEmail>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_LoginWithEmail>(
'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<plugins.lointReception.request.IReq_LoginWithEmailAfterEmailTokenAquired>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_LoginWithEmailAfterEmailTokenAquired>(
'loginWithEmailAfterEmailTokenAquired',
async (requestArg) => {
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) => {
const loginSession = await this.CLoginSession.getLoginSessionByRefreshToken(requestDataArg.refreshToken);
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(
'exchangeRefreshTokenAndTransferToken',
async (requestDataArg) => {
@@ -189,7 +189,7 @@ export class LoginSessionManager {
);
this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_ResetPassword>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_ResetPassword>(
'resetPassword',
async (requestDataArg) => {
const emailOfPasswordToReset = requestDataArg.email;
@@ -227,7 +227,7 @@ export class LoginSessionManager {
);
this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_SetNewPassword>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_SetNewPassword>(
'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<plugins.lointReception.request.IReq_ObtainDeviceId>('obtainDeviceId', async (reqData) => {
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_ObtainDeviceId>('obtainDeviceId', async (reqData) => {
reqData;
return {
deviceId: {
@@ -252,7 +252,7 @@ export class LoginSessionManager {
)
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
reqData.jwt;
return {
+3 -3
View File
@@ -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);
+2 -2
View File
@@ -17,7 +17,7 @@ export class OrganizationManager {
this.receptionRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_CreateOrganization>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_CreateOrganization>(
'createOrganization',
async (requestArg) => {
const nameIsAvailable = async () => {
@@ -64,7 +64,7 @@ export class OrganizationManager {
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_GetOrganizationById>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_GetOrganizationById>(
'getOrganizationById',
async (requestArg) => {
const verifiedJwt = await this.receptionRef.jwtManager.verifyJWTAndGetData(
+1 -1
View File
@@ -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,
@@ -14,7 +14,7 @@ export class RegistrationSessionManager {
this.receptionRef.typedrouter.addTypedRouter(this.typedRouter);
this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_FirstRegistration>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_FirstRegistration>(
'firstRegistrationRequest',
async (requestData) => {
// check for exiting User
@@ -60,7 +60,7 @@ export class RegistrationSessionManager {
);
this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_AfterRegistrationEmailClicked>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_AfterRegistrationEmailClicked>(
'afterRegistrationEmailClicked',
async (requestData) => {
console.log(requestData);
@@ -83,7 +83,7 @@ export class RegistrationSessionManager {
);
this.typedRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.lointReception.request.IReq_SetDataForRegistration>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_SetDataForRegistration>(
'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<plugins.lointReception.request.IReq_MobileVerificationForRegistration>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_MobileVerificationForRegistration>(
'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<plugins.lointReception.request.IReq_FinishRegistration>(
new plugins.typedrequest.TypedHandler<plugins.idpInterfaces.request.IReq_FinishRegistration>(
'finishRegistration',
async (requestData) => {
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()
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'];
}
+1 -1
View File
@@ -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) {
+3 -3
View File
@@ -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<User> {
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();
+25 -2
View File
@@ -19,7 +19,7 @@ export class UserManager {
constructor(receptionRefArg: Reception) {
this.receptionRef = receptionRefArg;
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 => {
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<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"
*/
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
});
+34 -23
View File
@@ -4,19 +4,19 @@ import * as plugins from './plugins.js';
export class IdpClient {
// INSTANCE PRIVATE
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);
},
};
// 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<plugins.lointReception.data.TLoginStatus>();
new plugins.smartrx.rxjs.Subject<plugins.idpInterfaces.data.TLoginStatus>();
public ssoStore = new plugins.webstore.WebStore({
storeName: 'idpglobalStore',
@@ -92,7 +92,7 @@ export class IdpClient {
public async getJwt(): Promise<string> {
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());
}
@@ -121,13 +121,13 @@ export class IdpClient {
}
public async refreshJwt(refreshTokenArg?: string): Promise<string> {
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<plugins.lointReception.request.IReq_RefreshJwt>(
new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_RefreshJwt>(
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<string> {
public async getTransferToken(appDataArg?: plugins.idpInterfaces.data.IApp): Promise<string> {
const jwt = await this.performJwtHousekeeping();
const extractedJwt = await this.helpers.extractDataFromJwtString(jwt);
const getTransferToken =
new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_ExchangeRefreshTokenAndTransferToken>(
new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_ExchangeRefreshTokenAndTransferToken>(
this.parsedReceptionUrl.toString(),
'exchangeRefreshTokenAndTransferToken'
);
@@ -188,7 +188,7 @@ export class IdpClient {
const transferToken = url.searchParams['transfertoken'];
if (transferToken) {
const getTransferToken =
new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_ExchangeRefreshTokenAndTransferToken>(
new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_ExchangeRefreshTokenAndTransferToken>(
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<plugins.lointReception.request.ILogoutRequest>(
this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.ILogoutRequest>(
'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<plugins.lointReception.request.IReq_CreateOrganization>(
this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_CreateOrganization>(
'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<plugins.lointReception.request.IReq_GetRolesAndOrganizationsForUserId>(
this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_GetRolesAndOrganizationsForUserId>(
'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<plugins.lointReception.request.IReq_UpdatePaymentMethod>(
this.typedsocket.createTypedRequest<plugins.idpInterfaces.request.IReq_UpdatePaymentMethod>(
'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<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 () {
return new plugins.typedrequest.TypedRequest<plugins.lointReception.request.IReq_AfterRegistrationEmailClicked>(
return new plugins.typedrequest.TypedRequest<plugins.idpInterfaces.request.IReq_AfterRegistrationEmailClicked>(
this.idpClientArg.parsedReceptionUrl.toString(),
'afterRegistrationEmailClicked'
);
}
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(),
'setDataForRegistration'
);
}
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(),
'mobileVerificationForRegistration'
);
@@ -33,28 +33,28 @@ export class IdpRequests {
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(),
'finishRegistration'
);
}
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(),
'loginWithEmailOrUsernameAndPassword'
);
}
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(),
'refreshJwt'
);
}
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(),
'exchangeRefreshTokenAndTransferToken'
);
+2 -2
View File
@@ -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';
@@ -74,3 +74,13 @@ export interface IReq_GetRolesAndOrganizationsForUserId
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 = {
name: '@idp.global/idp.global',
version: '1.3.0',
version: '1.4.0',
description: 'An identity provider software managing user authentications, registrations, and sessions.'
}
+1 -1
View File
@@ -102,7 +102,7 @@ export class IdpAccountContent extends DeesElement {
const viewcontainer: HTMLDivElement = this.shadowRoot.querySelector('.viewcontainer');
const cleanupViews = async () => {
for (const child of viewcontainer.children) {
for (const child of Array.from(viewcontainer.children)) {
viewcontainer.removeChild(child);
}
};
+75 -30
View File
@@ -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`
<style></style>
<div class="commitinfo">idp.global v${commitinfo.version}</div>
<div class="navigationGroupLabel">Account Settings</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>
<dees-input-dropdown .label=${'choose org:'}
<dees-input-dropdown
.label=${'choose org:'}
@selectedOption=${(eventArg: CustomEvent) => {
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)
);
}}
></dees-input-dropdown>
${this.options.map(option => {
return html`
<div class="navigationOption">
${option.text}
</div>
`;
${this.options.map((option) => {
return html` <div class="navigationOption">${option.text}</div> `;
})}
<div class="navigationGroupLabel">Account Settings</div>
`;
}
@@ -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;
});
}
}
+52 -15
View File
@@ -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`
<style></style>
<h1>idp.global</h1>
<div class="textbox">
Do you want to sign in or register?
<dees-button @click=${async () => {
${resolveExec(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>
await idpState.idpClient.determineLoginStatus();
const data = await idpState.idpClient.whoIs().catch();
if (data?.user) {
return html`
Hello ${data.user.data.name}!
<dees-button
@click=${async () => {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/account');
}}
>Manage your account</dees-button
>
<dees-button
@click=${async () => {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/logout');
}}
>Logout</dees-button
>
`
}
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
>
`;
})}
</div>
<div class="textbox">
@@ -82,10 +115,14 @@ export class IdpWelcome extends DeesElement {
</div>
<div class="textbox">
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>
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>
`;
}
+9 -1
View File
@@ -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(),