Remove unused files and configurations

This commit is contained in:
Simon Larsen
2023-12-25 12:42:20 +00:00
parent 25fd18b958
commit 4359b74f26
31 changed files with 9 additions and 7371 deletions

View File

@@ -137,20 +137,6 @@ jobs:
- run: cd CommonServer && npm install
- run: cd Home && npm install && npm run compile && npm run dep-check
compile-identity:
runs-on: ubuntu-latest
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 18.3.0
- run: cd Common && npm install
- run: cd Model && npm install
- run: cd CommonServer && npm install
- run: cd Identity && npm install && npm run compile && npm run dep-check
compile-notification:
runs-on: ubuntu-latest

View File

@@ -133,21 +133,6 @@ jobs:
- name: build docker image
run: sudo docker build -f ./Home/Dockerfile .
docker-build-identity:
runs-on: ubuntu-latest
env:
CI_PIPELINE_ID: ${{github.run_number}}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Preinstall
run: npm run prerun
# build image for identity
- name: build docker image
run: sudo docker build -f ./Identity/Dockerfile .
docker-build-notification:
runs-on: ubuntu-latest

View File

@@ -690,65 +690,6 @@ jobs:
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
identity-docker-image-deploy:
needs: generate-build-number
runs-on: ubuntu-latest
steps:
- name: Docker Meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
oneuptime/identity
ghcr.io/oneuptime/identity
tags: |
type=raw,value=release,enable=true
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v2
with:
node-version: 18.3.0
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Generate Dockerfile from Dockerfile.tpl
run: npm run prerun
# Build and deploy identity.
- name: Login to Docker Hub
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
file: ./Identity/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
home-docker-image-deploy:
needs: generate-build-number

View File

@@ -633,67 +633,6 @@ jobs:
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
identity-docker-image-deploy:
needs: generate-build-number
runs-on: ubuntu-latest
steps:
- name: Docker Meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
oneuptime/identity
ghcr.io/oneuptime/identity
tags: |
type=raw,value=test,enable=true
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v2
with:
node-version: 18.3.0
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Generate Dockerfile from Dockerfile.tpl
run: npm run prerun
# Build and deploy identity.
- name: Login to Docker Hub
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
file: ./Identity/Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_SHA=${{ github.sha }}
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
home-docker-image-deploy:
needs: generate-build-number
runs-on: ubuntu-latest

View File

@@ -33,15 +33,7 @@ const DashboardFooter: () => JSX.Element = () => {
{
name: 'Dashboard',
path: '/dashboard',
},
{
name: 'Notification',
path: '/notification',
},
{
name: 'Identity Service',
path: '/identity',
},
}
];
for (const app of apps) {

View File

@@ -33,15 +33,7 @@ const DashboardFooter: () => JSX.Element = () => {
{
name: 'Dashboard',
path: '/dashboard',
},
{
name: 'Notification',
path: '/notification',
},
{
name: 'Identity Service',
path: '/identity',
},
}
];
for (const app of apps) {

View File

@@ -33,12 +33,8 @@
value: {{ $.Release.Name }}-ingestor.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
- name: SERVER_TEST_SERVER_HOSTNAME
value: {{ $.Release.Name }}-test-server.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
- name: SERVER_FILE_HOSTNAME
value: {{ $.Release.Name }}-file.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
- name: SERVER_HOME_HOSTNAME
value: {{ $.Release.Name }}-home.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
- name: SERVER_IDENTITY_HOSTNAME
value: {{ $.Release.Name }}-identity.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
- name: SERVER_NOTIFICATION_HOSTNAME
value: {{ $.Release.Name }}-notification.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
- name: OTEL_COLLECTOR_HOSTNAME

View File

@@ -1 +0,0 @@
*.js text eol=lf

29
Identity/.gitignore vendored
View File

@@ -1,29 +0,0 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
#/backend/node_modules
/kubernetes
/node_modules
.idea
# misc
.DS_Store
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn.lock
**/*/paymentService.test.js
apiTest.rest
application_security_dir
container_security_dir
# coverage
/coverage
/.nyc_output
/greenlock.d/config.json
/greenlock.d/config.json.bak

View File

@@ -1,612 +0,0 @@
import {
IsBillingEnabled,
EncryptionSecret,
} from 'CommonServer/EnvironmentConfig';
import { AccountsRoute } from 'Common/ServiceRoute';
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import BadRequestException from 'Common/Types/Exception/BadRequestException';
import { JSONObject } from 'Common/Types/JSON';
import User from 'Model/Models/User';
import EmailVerificationTokenService from 'CommonServer/Services/EmailVerificationTokenService';
import UserService from 'CommonServer/Services/UserService';
import ObjectID from 'Common/Types/ObjectID';
import EmailVerificationToken from 'Model/Models/EmailVerificationToken';
import BadDataException from 'Common/Types/Exception/BadDataException';
import MailService from 'CommonServer/Services/MailService';
import EmailTemplateType from 'Common/Types/Email/EmailTemplateType';
import URL from 'Common/Types/API/URL';
import Response from 'CommonServer/Utils/Response';
import JSONWebToken from 'CommonServer/Utils/JsonWebToken';
import OneUptimeDate from 'Common/Types/Date';
import PositiveNumber from 'Common/Types/PositiveNumber';
import Route from 'Common/Types/API/Route';
import logger from 'CommonServer/Utils/Logger';
import PartialEntity from 'Common/Types/Database/PartialEntity';
import Email from 'Common/Types/Email';
import Name from 'Common/Types/Name';
import AuthenticationEmail from '../Utils/AuthenticationEmail';
import AccessTokenService from 'CommonServer/Services/AccessTokenService';
import Hostname from 'Common/Types/API/Hostname';
import Protocol from 'Common/Types/API/Protocol';
import DatabaseConfig from 'CommonServer/DatabaseConfig';
import CookieUtil from 'CommonServer/Utils/Cookie';
import BaseModel from 'Common/Models/BaseModel';
const router: ExpressRouter = Express.getRouter();
router.post(
'/signup',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
if (await DatabaseConfig.shouldDisableSignup()) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException(
'Sign up is disabled on this OneUptime Server. Please contact your server admin to enable it.'
)
);
}
const data: JSONObject = req.body['data'];
/* Creating a type that is a partial of the TBaseModel type. */
const partialUser: PartialEntity<User> = data;
if (IsBillingEnabled) {
//ALERT: Delete data.role so user don't accidently sign up as master-admin from the API.
partialUser.isMasterAdmin = false;
partialUser.isEmailVerified = false;
} else {
// IF its not a saas service then we will make the email verified.
// check if there are more than one user and if there is then we will not make the user master admin.
const userCount: PositiveNumber = await UserService.countBy({
props: {
isRoot: true,
},
query: {},
});
partialUser.isMasterAdmin = userCount.isZero(); // if the user count is 0 then make the first user master admin.
partialUser.isEmailVerified = true;
}
const alreadySavedUser: User | null = await UserService.findOneBy({
query: { email: partialUser.email as Email },
select: {
_id: true,
password: true,
},
props: {
isRoot: true,
},
});
if (alreadySavedUser && alreadySavedUser.password) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
`User with email ${partialUser.email} already exists.`
)
);
}
let savedUser: User | null = null;
if (alreadySavedUser) {
//@ts-ignore
savedUser = await UserService.updateOneByIdAndFetch({
id: alreadySavedUser.id!,
data: partialUser,
select: {
email: true,
_id: true,
name: true,
isMasterAdmin: true,
},
props: {
isRoot: true,
},
});
} else {
const user: User = BaseModel.fromJSON(
partialUser as JSONObject,
User
) as User;
savedUser = await UserService.create({
data: user,
props: {
isRoot: true,
},
});
}
const generatedToken: ObjectID = ObjectID.generate();
const emailVerificationToken: EmailVerificationToken =
new EmailVerificationToken();
emailVerificationToken.userId = savedUser?.id as ObjectID;
emailVerificationToken.email = savedUser?.email as Email;
emailVerificationToken.token = generatedToken;
emailVerificationToken.expires = OneUptimeDate.getOneDayAfter();
await EmailVerificationTokenService.create({
data: emailVerificationToken,
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
MailService.sendMail({
toEmail: partialUser.email as Email,
subject: 'Welcome to OneUptime. Please verify your email.',
templateType: EmailTemplateType.SignupWelcomeEmail,
vars: {
name: (partialUser.name! as Name).toString(),
tokenVerifyUrl: new URL(
httpProtocol,
host,
new Route(AccountsRoute.toString()).addRoute(
'/verify-email/' + generatedToken.toString()
)
).toString(),
homeUrl: new URL(httpProtocol, host).toString(),
},
}).catch((err: Error) => {
logger.error(err);
});
if (savedUser) {
// Refresh Permissions for this user here.
await AccessTokenService.refreshUserAllPermissions(
savedUser.id!
);
const token: string = JSONWebToken.sign(
savedUser,
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
);
// Set a cookie with token.
CookieUtil.setCookie(res, CookieUtil.getUserTokenKey(), token, {
maxAge: OneUptimeDate.getMillisecondsInDays(
new PositiveNumber(30)
),
httpOnly: true,
});
return Response.sendEntityResponse(req, res, savedUser, User);
}
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Failed to create a user')
);
} catch (err) {
return next(err);
}
}
);
router.post(
'/forgot-password',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body['data'];
const user: User = BaseModel.fromJSON(
data as JSONObject,
User
) as User;
const alreadySavedUser: User | null = await UserService.findOneBy({
query: { email: user.email! },
select: {
_id: true,
password: true,
name: true,
email: true,
isMasterAdmin: true,
},
props: {
isRoot: true,
},
});
if (alreadySavedUser && alreadySavedUser.password) {
const token: string = ObjectID.generate().toString();
await UserService.updateOneBy({
query: {
_id: alreadySavedUser._id!,
},
data: {
resetPasswordToken: token,
resetPasswordExpires: OneUptimeDate.getOneDayAfter(),
},
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
MailService.sendMail({
toEmail: user.email!,
subject: 'Password Reset Request for OneUptime',
templateType: EmailTemplateType.ForgotPassword,
vars: {
homeURL: new URL(httpProtocol, host).toString(),
tokenVerifyUrl: new URL(
httpProtocol,
host,
new Route(AccountsRoute.toString()).addRoute(
'/reset-password/' + token
)
).toString(),
},
}).catch((err: Error) => {
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
}
return Response.sendErrorResponse(
req,
res,
new BadDataException(
`No user is registered with ${user.email?.toString()}. Please sign up for a new account.`
)
);
} catch (err) {
return next(err);
}
}
);
router.post(
'/verify-email',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body['data'];
const token: EmailVerificationToken = BaseModel.fromJSON(
data as JSONObject,
EmailVerificationToken
) as EmailVerificationToken;
const alreadySavedToken: EmailVerificationToken | null =
await EmailVerificationTokenService.findOneBy({
query: { token: token.token! },
select: {
_id: true,
userId: true,
email: true,
expires: true,
},
props: {
isRoot: true,
},
});
if (!alreadySavedToken) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Invalid link. Please try to log in and we will resend you another link which you should be able to verify email with.'
)
);
}
if (OneUptimeDate.hasExpired(alreadySavedToken.expires!)) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Link expired. Please try to log in and we will resend you another link which you should be able to verify email with.'
)
);
}
const user: User | null = await UserService.findOneBy({
query: {
email: alreadySavedToken.email!,
},
props: {
isRoot: true,
},
select: {
_id: true,
email: true,
},
});
if (!user) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Invalid link. Please try to log in and we will resend you another link which you should be able to verify email with.'
)
);
}
await UserService.updateOneBy({
query: {
_id: user._id!,
},
data: {
isEmailVerified: true,
},
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
MailService.sendMail({
toEmail: user.email!,
subject: 'Email Verified.',
templateType: EmailTemplateType.EmailVerified,
vars: {
homeURL: new URL(httpProtocol, host).toString(),
},
}).catch((err: Error) => {
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);
}
}
);
router.post(
'/reset-password',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body['data'];
const user: User = BaseModel.fromJSON(
data as JSONObject,
User
) as User;
await user.password?.hashValue(EncryptionSecret);
const alreadySavedUser: User | null = await UserService.findOneBy({
query: {
resetPasswordToken:
(user.resetPasswordToken as string) || '',
},
select: {
_id: true,
password: true,
name: true,
email: true,
isMasterAdmin: true,
resetPasswordExpires: true,
},
props: {
isRoot: true,
},
});
if (!alreadySavedUser) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Invalid link. Please go to forgot password page again and request a new link.'
)
);
}
if (
alreadySavedUser &&
OneUptimeDate.hasExpired(alreadySavedUser.resetPasswordExpires!)
) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Expired link. Please go to forgot password page again and request a new link.'
)
);
}
await UserService.updateOneById({
id: alreadySavedUser.id!,
data: {
password: user.password!,
resetPasswordToken: null!,
resetPasswordExpires: null!,
},
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
MailService.sendMail({
toEmail: alreadySavedUser.email!,
subject: 'Password Changed.',
templateType: EmailTemplateType.PasswordChanged,
vars: {
homeURL: new URL(httpProtocol, host).toString(),
},
}).catch((err: Error) => {
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);
}
}
);
router.post(
'/logout',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
CookieUtil.removeAllCookies(req, res);
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);
}
}
);
router.post(
'/login',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body['data'];
const user: User = BaseModel.fromJSON(
data as JSONObject,
User
) as User;
await user.password?.hashValue(EncryptionSecret);
const alreadySavedUser: User | null = await UserService.findOneBy({
query: { email: user.email! },
select: {
_id: true,
password: true,
name: true,
email: true,
isMasterAdmin: true,
isEmailVerified: true,
profilePictureId: true,
},
props: {
isRoot: true,
},
});
if (alreadySavedUser) {
if (!alreadySavedUser.password) {
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'You have not signed up so far. Please go to the registration page to sign up.'
)
);
}
if (!alreadySavedUser.isEmailVerified) {
await AuthenticationEmail.sendVerificationEmail(
alreadySavedUser
);
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Email is not verified. We have sent you an email with the verification link. Please do not forget to check spam.'
)
);
}
// Refresh Permissions for this user here.
await AccessTokenService.refreshUserAllPermissions(
alreadySavedUser.id!
);
if (
alreadySavedUser.password.toString() ===
user.password!.toString()
) {
const token: string = JSONWebToken.sign(
alreadySavedUser,
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
);
// Set a cookie with token.
CookieUtil.setCookie(
res,
CookieUtil.getUserTokenKey(),
token,
{
maxAge: OneUptimeDate.getMillisecondsInDays(
new PositiveNumber(30)
),
httpOnly: true,
}
);
return Response.sendEntityResponse(
req,
res,
alreadySavedUser,
User
);
}
}
return Response.sendErrorResponse(
req,
res,
new BadDataException(
'Invalid login: Email or password does not match.'
)
);
} catch (err) {
return next(err);
}
}
);
export default router;

View File

@@ -1,79 +0,0 @@
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import BadDataException from 'Common/Types/Exception/BadDataException';
import Reseller from 'Model/Models/Reseller';
import ResellerService from 'CommonServer/Services/ResellerService';
import JSONWebToken from 'CommonServer/Utils/JsonWebToken';
import OneUptimeDate from 'Common/Types/Date';
import Response from 'CommonServer/Utils/Response';
const router: ExpressRouter = Express.getRouter();
router.post(
'/reseller/auth/:resellerid',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const resellerId: string | undefined = req.params['resellerid'];
if (!resellerId) {
throw new BadDataException('Reseller ID not found');
}
const username: string = req.body['username'];
const password: string = req.body['password'];
if (!username) {
throw new BadDataException('Username not found');
}
if (!password) {
throw new BadDataException('Password not found');
}
// get the reseller user.
const reseller: Reseller | null = await ResellerService.findOneBy({
query: {
resellerId: resellerId,
username: username,
password: password,
},
select: {
_id: true,
resellerId: true,
},
props: {
isRoot: true,
},
});
if (!reseller) {
throw new BadDataException(
'Reseller not found or username and password is incorrect'
);
}
// if found then generate a token and return it.
const token: string = JSONWebToken.sign(
{ resellerId: resellerId },
OneUptimeDate.getDayInSeconds(365)
);
return Response.sendJsonObjectResponse(req, res, {
access: token,
});
} catch (err) {
return next(err);
}
}
);
export default router;

View File

@@ -1,386 +0,0 @@
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import BadRequestException from 'Common/Types/Exception/BadRequestException';
import ServerException from 'Common/Types/Exception/ServerException';
import Response from 'CommonServer/Utils/Response';
import ProjectSSO from 'Model/Models/ProjectSso';
import ProjectSSOService from 'CommonServer/Services/ProjectSsoService';
import ObjectID from 'Common/Types/ObjectID';
import xml2js from 'xml2js';
import { JSONObject } from 'Common/Types/JSON';
import logger from 'CommonServer/Utils/Logger';
import Email from 'Common/Types/Email';
import User from 'Model/Models/User';
import UserService from 'CommonServer/Services/UserService';
import AuthenticationEmail from '../Utils/AuthenticationEmail';
import OneUptimeDate from 'Common/Types/Date';
import PositiveNumber from 'Common/Types/PositiveNumber';
import JSONWebToken from 'CommonServer/Utils/JsonWebToken';
import URL from 'Common/Types/API/URL';
import { DashboardRoute } from 'Common/ServiceRoute';
import Route from 'Common/Types/API/Route';
import TeamMember from 'Model/Models/TeamMember';
import TeamMemberService from 'CommonServer/Services/TeamMemberService';
import AccessTokenService from 'CommonServer/Services/AccessTokenService';
import SSOUtil from '../Utils/SSO';
import Exception from 'Common/Types/Exception/Exception';
import Hostname from 'Common/Types/API/Hostname';
import Protocol from 'Common/Types/API/Protocol';
import DatabaseConfig from 'CommonServer/DatabaseConfig';
import CookieUtil from 'CommonServer/Utils/Cookie';
const router: ExpressRouter = Express.getRouter();
router.get(
'/sso/:projectId/:projectSsoId',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
if (!req.params['projectId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Project ID not found')
);
}
if (!req.params['projectSsoId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Project SSO ID not found')
);
}
const projectSSO: ProjectSSO | null =
await ProjectSSOService.findOneBy({
query: {
projectId: new ObjectID(req.params['projectId']),
_id: req.params['projectSsoId'],
isEnabled: true,
},
select: {
signOnURL: true,
},
props: {
isRoot: true,
},
});
if (!projectSSO) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('SSO Config not found')
);
}
// redirect to Identity Provider.
if (!projectSSO.signOnURL) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Sign On URL not found')
);
}
return Response.redirect(req, res, projectSSO.signOnURL);
} catch (err) {
return next(err);
}
}
);
router.post(
'/idp-login/:projectId/:projectSsoId',
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
const samlResponseBase64: string = req.body.SAMLResponse;
const samlResponse: string = Buffer.from(
samlResponseBase64,
'base64'
).toString();
const response: JSONObject = await xml2js.parseStringPromise(
samlResponse
);
let issuerUrl: string = '';
let email: Email | null = null;
if (!req.params['projectId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Project ID not found')
);
}
if (!req.params['projectSsoId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Project SSO ID not found')
);
}
const projectSSO: ProjectSSO | null =
await ProjectSSOService.findOneBy({
query: {
projectId: new ObjectID(req.params['projectId']),
_id: req.params['projectSsoId'],
isEnabled: true,
},
select: {
signOnURL: true,
issuerURL: true,
publicCertificate: true,
teams: {
_id: true,
},
},
props: {
isRoot: true,
},
});
if (!projectSSO) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('SSO Config not found')
);
}
// redirect to Identity Provider.
if (!projectSSO.issuerURL) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Issuer URL not found')
);
}
// redirect to Identity Provider.
if (!projectSSO.signOnURL) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Sign on URL not found')
);
}
if (!projectSSO.publicCertificate) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Public Certificate not found')
);
}
try {
SSOUtil.isPayloadValid(response);
if (
!SSOUtil.isSignatureValid(
samlResponse,
projectSSO.publicCertificate
)
) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException(
'Signature is not valid or Public Certificate configured with this SSO provider is not valid'
)
);
}
issuerUrl = SSOUtil.getIssuer(response);
email = SSOUtil.getEmail(response);
} catch (err: unknown) {
if (err instanceof Exception) {
return Response.sendErrorResponse(req, res, err);
}
return Response.sendErrorResponse(
req,
res,
new ServerException()
);
}
if (projectSSO.issuerURL.toString() !== issuerUrl) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Issuer URL does not match')
);
}
// Check if he already belongs to the project, If he does - then log in.
let alreadySavedUser: User | null = await UserService.findOneBy({
query: { email: email },
select: {
_id: true,
name: true,
email: true,
isMasterAdmin: true,
isEmailVerified: true,
profilePictureId: true,
},
props: {
isRoot: true,
},
});
let isNewUser: boolean = false;
if (!alreadySavedUser) {
// this should never happen because user is logged in before he signs in with SSO UNLESS he initiates the login though the IDP.
/// Create a user.
alreadySavedUser = await UserService.createByEmail(email, {
isRoot: true,
});
isNewUser = true;
}
// If he does not then add him to teams that he should belong and log in.
if (!alreadySavedUser.isEmailVerified && !isNewUser) {
await AuthenticationEmail.sendVerificationEmail(
alreadySavedUser
);
return Response.render(req, res, '../Views/Message.ejs', {
title: 'Email not verified.',
message:
'Email is not verified. We have sent you an email with the verification link. Please do not forget to check spam.',
});
}
// check if the user already belongs to the project
const teamMemberCount: PositiveNumber =
await TeamMemberService.countBy({
query: {
projectId: new ObjectID(
req.params['projectId'] as string
),
userId: alreadySavedUser.id!,
},
props: {
isRoot: true,
},
});
if (teamMemberCount.toNumber() === 0) {
// user not in project, add him to default teams.
if (!projectSSO.teams || projectSSO.teams.length === 0) {
return Response.render(req, res, '../Views/Message.ejs', {
title: 'No teams added.',
message:
'No teams have been added to this SSO config. Please contact your admin and have default teams added.',
});
}
for (const team of projectSSO.teams) {
// add user to team
let teamMember: TeamMember = new TeamMember();
teamMember.projectId = new ObjectID(
req.params['projectId'] as string
);
teamMember.userId = alreadySavedUser.id!;
teamMember.hasAcceptedInvitation = true;
teamMember.invitationAcceptedAt =
OneUptimeDate.getCurrentDate();
teamMember.teamId = team.id!;
teamMember = await TeamMemberService.create({
data: teamMember,
props: {
isRoot: true,
ignoreHooks: true,
},
});
}
}
if (isNewUser) {
return Response.render(req, res, '../Views/Message.ejs', {
title: 'You have not signed up so far.',
message:
'You need to sign up for an account on OneUptime with this email:' +
email.toString() +
'. Once you have signed up, you can use SSO to log in to your project.',
});
}
const projectId: ObjectID = new ObjectID(
req.params['projectId'] as string
);
const token: string = JSONWebToken.sign(
{
userId: alreadySavedUser.id!,
projectId: projectId,
email: email,
isMasterAdmin: false,
},
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
);
// Refresh Permissions for this user here.
await AccessTokenService.refreshUserAllPermissions(
alreadySavedUser.id!
);
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
CookieUtil.setCookie(
res,
CookieUtil.getUserSSOKey(projectId),
token,
{
maxAge: OneUptimeDate.getMillisecondsInDays(
new PositiveNumber(30)
),
httpOnly: true,
}
);
return Response.redirect(
req,
res,
new URL(
httpProtocol,
host,
new Route(DashboardRoute.toString()).addRoute(
'/' + req.params['projectId']
),
'sso_token=' + token
)
);
} catch (err) {
logger.error(err);
Response.sendErrorResponse(req, res, new ServerException());
}
}
);
export default router;

View File

@@ -1,430 +0,0 @@
import { EncryptionSecret } from 'CommonServer/EnvironmentConfig';
import { FileRoute } from 'Common/ServiceRoute';
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import { JSONObject } from 'Common/Types/JSON';
import StatusPagePrivateUserService from 'CommonServer/Services/StatusPagePrivateUserService';
import ObjectID from 'Common/Types/ObjectID';
import BadDataException from 'Common/Types/Exception/BadDataException';
import MailService from 'CommonServer/Services/MailService';
import EmailTemplateType from 'Common/Types/Email/EmailTemplateType';
import URL from 'Common/Types/API/URL';
import Response from 'CommonServer/Utils/Response';
import JSONWebToken from 'CommonServer/Utils/JsonWebToken';
import OneUptimeDate from 'Common/Types/Date';
import PositiveNumber from 'Common/Types/PositiveNumber';
import logger from 'CommonServer/Utils/Logger';
import JSONFunctions from 'Common/Types/JSONFunctions';
import StatusPagePrivateUser from 'Model/Models/StatusPagePrivateUser';
import StatusPage from 'Model/Models/StatusPage';
import StatusPageService from 'CommonServer/Services/StatusPageService';
import Protocol from 'Common/Types/API/Protocol';
import Hostname from 'Common/Types/API/Hostname';
import DatabaseConfig from 'CommonServer/DatabaseConfig';
import CookieUtil from 'CommonServer/Utils/Cookie';
import BaseModel from 'Common/Models/BaseModel';
const router: ExpressRouter = Express.getRouter();
router.post(
'/logout/:statuspageid',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
if (!req.params['statuspageid']) {
throw new BadDataException('Status Page ID is required.');
}
const statusPageId: ObjectID = new ObjectID(
req.params['statuspageid'].toString()
);
CookieUtil.removeCookie(
res,
CookieUtil.getUserTokenKey(statusPageId)
); // remove the cookie.
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);
}
}
);
router.post(
'/forgot-password',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body['data'];
if (!data['email']) {
throw new BadDataException('Email is required.');
}
const user: StatusPagePrivateUser = BaseModel.fromJSON(
data as JSONObject,
StatusPagePrivateUser
) as StatusPagePrivateUser;
if (!user.statusPageId) {
throw new BadDataException('Status Page ID is required.');
}
const statusPage: StatusPage | null =
await StatusPageService.findOneById({
id: user.statusPageId!,
props: {
isRoot: true,
ignoreHooks: true,
},
select: {
_id: true,
name: true,
pageTitle: true,
logoFileId: true,
requireSsoForLogin: true,
projectId: true,
},
});
if (!statusPage) {
throw new BadDataException('Status Page not found');
}
if (statusPage.requireSsoForLogin) {
throw new BadDataException(
'Status Page supports authentication by SSO. You cannot use email and password for authentication.'
);
}
const statusPageName: string | undefined =
statusPage.pageTitle || statusPage.name;
const statusPageURL: string =
await StatusPageService.getStatusPageURL(statusPage.id!);
const alreadySavedUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
email: user.email!,
statusPageId: user.statusPageId!,
},
select: {
_id: true,
password: true,
email: true,
},
props: {
isRoot: true,
},
});
if (alreadySavedUser) {
const token: string = ObjectID.generate().toString();
await StatusPagePrivateUserService.updateOneBy({
query: {
_id: alreadySavedUser._id!,
},
data: {
resetPasswordToken: token,
resetPasswordExpires: OneUptimeDate.getOneDayAfter(),
},
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
MailService.sendMail(
{
toEmail: user.email!,
subject: 'Password Reset Request for ' + statusPageName,
templateType:
EmailTemplateType.StatusPageForgotPassword,
vars: {
statusPageName: statusPageName!,
logoUrl: statusPage.logoFileId
? new URL(httpProtocol, host)
.addRoute(FileRoute)
.addRoute(
'/image/' + statusPage.logoFileId
)
.toString()
: '',
homeURL: statusPageURL,
tokenVerifyUrl: URL.fromString(statusPageURL)
.addRoute('/reset-password/' + token)
.toString(),
},
},
{
projectId: statusPage.projectId!,
}
).catch((err: Error) => {
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
}
throw new BadDataException(
`No user is registered with ${user.email?.toString()}`
);
} catch (err) {
return next(err);
}
}
);
router.post(
'/reset-password',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = JSONFunctions.deserialize(
req.body['data']
);
if (!data['statusPageId']) {
throw new BadDataException('Status Page ID is required.');
}
const user: StatusPagePrivateUser = BaseModel.fromJSON(
data as JSONObject,
StatusPagePrivateUser
) as StatusPagePrivateUser;
await user.password?.hashValue(EncryptionSecret);
const alreadySavedUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
statusPageId: new ObjectID(
data['statusPageId'].toString()
),
resetPasswordToken:
(user.resetPasswordToken as string) || '',
},
select: {
_id: true,
password: true,
email: true,
resetPasswordExpires: true,
},
props: {
isRoot: true,
},
});
if (!alreadySavedUser) {
throw new BadDataException(
'Invalid link. Please go to forgot password page again and request a new link.'
);
}
if (
alreadySavedUser &&
OneUptimeDate.hasExpired(alreadySavedUser.resetPasswordExpires!)
) {
throw new BadDataException(
'Expired link. Please go to forgot password page again and request a new link.'
);
}
const statusPage: StatusPage | null =
await StatusPageService.findOneById({
id: new ObjectID(data['statusPageId'].toString()),
props: {
isRoot: true,
ignoreHooks: true,
},
select: {
_id: true,
name: true,
pageTitle: true,
logoFileId: true,
requireSsoForLogin: true,
projectId: true,
},
});
if (!statusPage) {
throw new BadDataException('Status Page not found');
}
if (statusPage.requireSsoForLogin) {
throw new BadDataException(
'Status Page supports authentication by SSO. You cannot use email and password for authentication.'
);
}
const statusPageName: string | undefined =
statusPage.pageTitle || statusPage.name;
const statusPageURL: string =
await StatusPageService.getStatusPageURL(statusPage.id!);
await StatusPagePrivateUserService.updateOneById({
id: alreadySavedUser.id!,
data: {
password: user.password!,
resetPasswordToken: null!,
resetPasswordExpires: null!,
},
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol =
await DatabaseConfig.getHttpProtocol();
MailService.sendMail(
{
toEmail: alreadySavedUser.email!,
subject: 'Password Changed.',
templateType: EmailTemplateType.StatusPagePasswordChanged,
vars: {
homeURL: statusPageURL,
statusPageName: statusPageName || '',
logoUrl: statusPage.logoFileId
? new URL(httpProtocol, host)
.addRoute(FileRoute)
.addRoute('/image/' + statusPage.logoFileId)
.toString()
: '',
},
},
{
projectId: statusPage.projectId!,
}
).catch((err: Error) => {
logger.error(err);
});
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);
}
}
);
router.post(
'/login',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body['data'];
const user: StatusPagePrivateUser = BaseModel.fromJSON(
data as JSONObject,
StatusPagePrivateUser
) as StatusPagePrivateUser;
if (!user.statusPageId) {
throw new BadDataException('Status Page ID not found');
}
const statusPage: StatusPage | null =
await StatusPageService.findOneById({
id: user.statusPageId,
props: {
isRoot: true,
ignoreHooks: true,
},
select: {
requireSsoForLogin: true,
},
});
if (!statusPage) {
throw new BadDataException('Status Page not found');
}
if (statusPage.requireSsoForLogin) {
throw new BadDataException(
'Status Page supports authentication by SSO. You cannot use email and password for authentication.'
);
}
await user.password?.hashValue(EncryptionSecret);
const alreadySavedUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: {
email: user.email!,
password: user.password!,
statusPageId: user.statusPageId!,
},
select: {
_id: true,
password: true,
email: true,
statusPageId: true,
},
props: {
isRoot: true,
},
});
if (alreadySavedUser) {
const token: string = JSONWebToken.sign(
alreadySavedUser,
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
);
CookieUtil.setCookie(
res,
CookieUtil.getUserTokenKey(alreadySavedUser.statusPageId!),
token,
{
httpOnly: true,
maxAge: OneUptimeDate.getMillisecondsInDays(
new PositiveNumber(30)
),
}
);
return Response.sendEntityResponse(
req,
res,
alreadySavedUser,
StatusPagePrivateUser,
{
miscData: {
token: token,
},
}
);
}
throw new BadDataException(
'Invalid login: Email or password does not match.'
);
} catch (err) {
return next(err);
}
}
);
export default router;

View File

@@ -1,308 +0,0 @@
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import BadRequestException from 'Common/Types/Exception/BadRequestException';
import ServerException from 'Common/Types/Exception/ServerException';
import Response from 'CommonServer/Utils/Response';
import StatusPageSsoService from 'CommonServer/Services/StatusPageSsoService';
import ObjectID from 'Common/Types/ObjectID';
import xml2js from 'xml2js';
import { JSONObject } from 'Common/Types/JSON';
import logger from 'CommonServer/Utils/Logger';
import Email from 'Common/Types/Email';
import OneUptimeDate from 'Common/Types/Date';
import PositiveNumber from 'Common/Types/PositiveNumber';
import JSONWebToken from 'CommonServer/Utils/JsonWebToken';
import URL from 'Common/Types/API/URL';
import SSOUtil from '../Utils/SSO';
import Exception from 'Common/Types/Exception/Exception';
import StatusPageSSO from 'Model/Models/StatusPageSso';
import StatusPagePrivateUser from 'Model/Models/StatusPagePrivateUser';
import StatusPagePrivateUserService from 'CommonServer/Services/StatusPagePrivateUserService';
import HashedString from 'Common/Types/HashedString';
import StatusPageService from 'CommonServer/Services/StatusPageService';
import CookieUtil from 'CommonServer/Utils/Cookie';
const router: ExpressRouter = Express.getRouter();
router.get(
'/status-page-sso/:statusPageId/:statusPageSsoId',
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
if (!req.params['statusPageId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Status Page ID not found')
);
}
if (!req.params['statusPageSsoId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Status Page SSO ID not found')
);
}
const statusPageId: ObjectID = new ObjectID(
req.params['statusPageId']
);
const statusPageSSO: StatusPageSSO | null =
await StatusPageSsoService.findOneBy({
query: {
statusPageId: statusPageId,
_id: req.params['statusPageSsoId'],
isEnabled: true,
},
select: {
signOnURL: true,
},
props: {
isRoot: true,
},
});
if (!statusPageSSO) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('SSO Config not found')
);
}
// redirect to Identity Provider.
if (!statusPageSSO.signOnURL) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Sign On URL not found')
);
}
return Response.redirect(req, res, statusPageSSO.signOnURL);
} catch (err) {
return next(err);
}
}
);
router.post(
'/status-page-idp-login/:statusPageId/:statusPageSsoId',
async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
try {
const samlResponseBase64: string = req.body.SAMLResponse;
const samlResponse: string = Buffer.from(
samlResponseBase64,
'base64'
).toString();
const response: JSONObject = await xml2js.parseStringPromise(
samlResponse
);
let issuerUrl: string = '';
let email: Email | null = null;
if (!req.params['statusPageId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Status Page ID not found')
);
}
if (!req.params['statusPageSsoId']) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Status Page SSO ID not found')
);
}
const statusPageId: ObjectID = new ObjectID(
req.params['statusPageId']
);
const statusPageSSO: StatusPageSSO | null =
await StatusPageSsoService.findOneBy({
query: {
statusPageId: statusPageId,
_id: req.params['statusPageSsoId'],
isEnabled: true,
},
select: {
signOnURL: true,
issuerURL: true,
publicCertificate: true,
projectId: true,
},
props: {
isRoot: true,
},
});
if (!statusPageSSO) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('SSO Config not found')
);
}
if (!statusPageSSO.projectId) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('SSO Config Project ID not found')
);
}
const projectId: ObjectID = statusPageSSO.projectId;
// redirect to Identity Provider.
if (!statusPageSSO.issuerURL) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Issuer URL not found')
);
}
// redirect to Identity Provider.
if (!statusPageSSO.signOnURL) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Sign on URL not found')
);
}
if (!statusPageSSO.publicCertificate) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Public Certificate not found')
);
}
try {
SSOUtil.isPayloadValid(response);
if (
!SSOUtil.isSignatureValid(
samlResponse,
statusPageSSO.publicCertificate
)
) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Signature is not valid')
);
}
issuerUrl = SSOUtil.getIssuer(response);
email = SSOUtil.getEmail(response);
} catch (err: unknown) {
if (err instanceof Exception) {
return Response.sendErrorResponse(req, res, err);
}
return Response.sendErrorResponse(
req,
res,
new ServerException()
);
}
if (statusPageSSO.issuerURL.toString() !== issuerUrl) {
return Response.sendErrorResponse(
req,
res,
new BadRequestException('Issuer URL does not match')
);
}
// Check if he already belongs to the project, If he does - then log in.
let alreadySavedUser: StatusPagePrivateUser | null =
await StatusPagePrivateUserService.findOneBy({
query: { email: email, statusPageId: statusPageId },
select: {
_id: true,
email: true,
statusPageId: true,
projectId: true,
},
props: {
isRoot: true,
},
});
if (!alreadySavedUser) {
/// Create a user.
alreadySavedUser = new StatusPagePrivateUser();
alreadySavedUser.projectId = projectId;
alreadySavedUser.statusPageId = statusPageId;
alreadySavedUser.email = email;
alreadySavedUser.password = new HashedString(
ObjectID.generate().toString()
);
alreadySavedUser.isSsoUser = true;
alreadySavedUser = await StatusPagePrivateUserService.create({
data: alreadySavedUser,
props: { isRoot: true },
});
}
const token: string = JSONWebToken.sign(
alreadySavedUser,
OneUptimeDate.getSecondsInDays(new PositiveNumber(30))
);
CookieUtil.setCookie(
res,
CookieUtil.getUserTokenKey(alreadySavedUser.statusPageId!),
token,
{
httpOnly: true,
maxAge: OneUptimeDate.getMillisecondsInDays(
new PositiveNumber(30)
),
}
);
// get status page URL.
const statusPageURL: string =
await StatusPageService.getStatusPageFirstURL(statusPageId);
return Response.redirect(
req,
res,
URL.fromString(statusPageURL).addQueryParams({
token: token,
})
);
} catch (err) {
logger.error(err);
Response.sendErrorResponse(req, res, new ServerException());
}
}
);
export default router;

View File

@@ -1,74 +0,0 @@
#
# OneUptime-identity Dockerfile
#
# Pull base image nodejs image.
FROM node:21.2-alpine3.18
USER root
RUN mkdir /tmp/npm && chmod 2777 /tmp/npm && chown 1000:1000 /tmp/npm && npm config set cache /tmp/npm --global
ARG GIT_SHA
ARG APP_VERSION
ENV GIT_SHA=${GIT_SHA}
ENV APP_VERSION=${APP_VERSION}
# Install bash.
RUN apk add bash && apk add curl
# Install python
RUN apk update && apk add --no-cache --virtual .gyp python3 make g++
#Use bash shell by default
SHELL ["/bin/bash", "-c"]
RUN mkdir /usr/src
WORKDIR /usr/src/Common
COPY ./Common/package*.json /usr/src/Common/
RUN npm install
COPY ./Common /usr/src/Common
WORKDIR /usr/src/Model
COPY ./Model/package*.json /usr/src/Model/
RUN npm install
COPY ./Model /usr/src/Model
WORKDIR /usr/src/CommonServer
COPY ./CommonServer/package*.json /usr/src/CommonServer/
RUN npm install
COPY ./CommonServer /usr/src/CommonServer
ENV PRODUCTION=true
WORKDIR /usr/src/app
# Install app dependencies
COPY ./Identity/package*.json /usr/src/app/
RUN npm install
# Expose ports.
# - 3087: OneUptime-backend
EXPOSE 3087
{{ if eq .Env.ENVIRONMENT "development" }}
#Run the app
CMD [ "npm", "run", "dev" ]
{{ else }}
# Copy app source
COPY ./Identity /usr/src/app
# Bundle app source
RUN npm run compile
#Run the app
CMD [ "npm", "start" ]
{{ end }}

View File

@@ -1,259 +0,0 @@
{
"saml2p:Response": {
"$": {
"Destination": "http://localhost/identity/idp-login/19462af5-a3c5-414d-bef8-20681c708579/56489843-5440-4305-a46a-c64215451b65",
"ID": "id397086821029112924757763",
"IssueInstant": "2023-03-05T17:44:26.808Z",
"Version": "2.0",
"xmlns:saml2p": "urn:oasis:names:tc:SAML:2.0:protocol"
},
"saml2:Issuer": [
{
"_": "http://www.okta.com/exk4fi36tv3SJZtRv697",
"$": {
"Format": "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
"xmlns:saml2": "urn:oasis:names:tc:SAML:2.0:assertion"
}
}
],
"ds:Signature": [
{
"$": {
"xmlns:ds": "http://www.w3.org/2000/09/xmldsig#"
},
"ds:SignedInfo": [
{
"ds:CanonicalizationMethod": [
{
"$": {
"Algorithm": "http://www.w3.org/2001/10/xml-exc-c14n#"
}
}
],
"ds:SignatureMethod": [
{
"$": {
"Algorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
}
}
],
"ds:Reference": [
{
"$": {
"URI": "#id397086821029112924757763"
},
"ds:Transforms": [
{
"ds:Transform": [
{
"$": {
"Algorithm": "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
}
},
{
"$": {
"Algorithm": "http://www.w3.org/2001/10/xml-exc-c14n#"
}
}
]
}
],
"ds:DigestMethod": [
{
"$": {
"Algorithm": "http://www.w3.org/2001/04/xmlenc#sha256"
}
}
],
"ds:DigestValue": [
"+tsuTZP7BGip7e83ZYPts5m5cYrzMqhrARClHNoRbpc="
]
}
]
}
],
"ds:SignatureValue": [
"Bcq6j2LXUzrK7ZHSmvR/PkPrkNVmoeInyKxQOlAQ6CQPKSaEBn73jMlZU+AeaDmwwkb0UepX1yIiIkiX93202XDjeUxFe2QsZlKz7hm2JdZrTJTan1dg3sdSxwm3RAwGas03M7UDbtUuphdVfxO4aFavMAFlylXrvSN+dOE7pMpClSuIfk3ugmMysnfd0HlK7vosiD/GFEfUvpiVVyyzlJFdAijT1n4S5QkYPjBNJVkllwTiPTe7SVlmz/49fg16324UTczcuwOepFHNvqrskFT0T3pRDtFNdsnI94xpRYmTjJykdr59CshSElrZHZcne6zRkwb85pEn+qk3Npcg5A=="
],
"ds:KeyInfo": [
{
"ds:X509Data": [
{
"ds:X509Certificate": [
"MIIDqjCCApKgAwIBAgIGAYao8ch8MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYDVQQGEwJVUzETMBEG\nA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU\nMBIGA1UECwwLU1NPUHJvdmlkZXIxFjAUBgNVBAMMDXRyaWFsLTk5NTU3NzUxHDAaBgkqhkiG9w0B\nCQEWDWluZm9Ab2t0YS5jb20wHhcNMjMwMzAzMTkyNjQzWhcNMzMwMzAzMTkyNzQzWjCBlTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTAL\nBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRYwFAYDVQQDDA10cmlhbC05OTU1Nzc1\nMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAx2HI6ri2hhgrdkBvLz3YJ1InOY3gQsbT/s/wtCw1dE9dmZnsurPSUPGZsf9Cof8WoIvq\nTPpTDjS0g4wx0mVjY6qejmVF4OFUCHrJPDNvO0Mey2cfK4tCBtvFtnUsntl1c2HCfdi/mMNVV3Di\nTATlWeCMf++HBHE65HKO8B+PCRHbt2jYYT1CtBGGk9yFP4SN0iBAFE+az5QAf86iW2ZYuUmkt87G\nYxBSuwj9h1rW9g6yr2sDX+9cXBPB4/4nq5lKBzaAt/O+UMXBoMiWP2xh+KyyccOv13xtDJpBhZDH\nEVQp5X10I1bm5/Y8QpXG9qEd1C6pa76w4VoPernnYYRa9QIDAQABMA0GCSqGSIb3DQEBCwUAA4IB\nAQBrE+qga2ZbF99L3wa0oy9sfSq9/6B6E8KODNeYOZ6OCTXij8EMcKYZGRXV22qHr7AwA0MVfYi5\ntt5jAuHTnKBPHaoYzYjQlu7/QXbte8WoximdliQraiD/zAps61Qj+c1Pctt1dwH3xu2Ppx0P3KvL\nBNE/LDMSADNpTL/o0jQnOzH9KP47iCI8lzdboHtegXuAnlCLj3uSYFy/W4KPm1FZHjZFkmmZz0SH\n/W2tTtkPfeSC+c0G8IhhUHLJ2QUEmH4Sk+l4PM5Jklb4RnABUKfiuel1zKlBE5hpWcn4cYWrHwCl\n1NKiHj2mkWIwVey813T/7M+nk93WK1G6psCleczN"
]
}
]
}
]
}
],
"saml2p:Status": [
{
"$": {
"xmlns:saml2p": "urn:oasis:names:tc:SAML:2.0:protocol"
},
"saml2p:StatusCode": [
{
"$": {
"Value": "urn:oasis:names:tc:SAML:2.0:status:Success"
}
}
]
}
],
"saml2:Assertion": [
{
"$": {
"ID": "id397086821197064596402169",
"IssueInstant": "2023-03-05T17:44:26.808Z",
"Version": "2.0",
"xmlns:saml2": "urn:oasis:names:tc:SAML:2.0:assertion"
},
"saml2:Issuer": [
{
"_": "http://www.okta.com/exk4fi36tv3SJZtRv697",
"$": {
"Format": "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
"xmlns:saml2": "urn:oasis:names:tc:SAML:2.0:assertion"
}
}
],
"ds:Signature": [
{
"$": {
"xmlns:ds": "http://www.w3.org/2000/09/xmldsig#"
},
"ds:SignedInfo": [
{
"ds:CanonicalizationMethod": [
{
"$": {
"Algorithm": "http://www.w3.org/2001/10/xml-exc-c14n#"
}
}
],
"ds:SignatureMethod": [
{
"$": {
"Algorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
}
}
],
"ds:Reference": [
{
"$": {
"URI": "#id397086821197064596402169"
},
"ds:Transforms": [
{
"ds:Transform": [
{
"$": {
"Algorithm": "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
}
},
{
"$": {
"Algorithm": "http://www.w3.org/2001/10/xml-exc-c14n#"
}
}
]
}
],
"ds:DigestMethod": [
{
"$": {
"Algorithm": "http://www.w3.org/2001/04/xmlenc#sha256"
}
}
],
"ds:DigestValue": [
"eLop0iyvMdT62i2FD7hbULG3PfPuOsVaM/bBTgwBQJM="
]
}
]
}
],
"ds:SignatureValue": [
"CkCV6PDaVUckuxCwI23p//eS+SXI6VwJXoLmftW8waF5wGIDLku9nXK+McbcroWHMBvyXa+hOeoFLEtb9YCy37yQMohKRvacKXI7waOx85egMYcZtGXMrK4BGt7m+A9Kqbu0LO0b52W3HyIJxXDlnJFYq8QnQzdX62KujnhtS61rjKoud/2TBzlu/dY/EAnLcCd1YlR737nnABMmRisAnf8E2NfEQ6eJV/Pf7EeO8jdB/QOqOFR2nt6N+oeBf6UG0Gsj5RBt9SD2FwmDYgB0s2jW5LYhw3bY0/6M8vUrADpraedIUg+M8+yByiHS6QRHJMWNdeJcZRu8RY4gkSrLUQ=="
],
"ds:KeyInfo": [
{
"ds:X509Data": [
{
"ds:X509Certificate": [
"MIIDqjCCApKgAwIBAgIGAYao8ch8MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYDVQQGEwJVUzETMBEG\nA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU\nMBIGA1UECwwLU1NPUHJvdmlkZXIxFjAUBgNVBAMMDXRyaWFsLTk5NTU3NzUxHDAaBgkqhkiG9w0B\nCQEWDWluZm9Ab2t0YS5jb20wHhcNMjMwMzAzMTkyNjQzWhcNMzMwMzAzMTkyNzQzWjCBlTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTAL\nBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRYwFAYDVQQDDA10cmlhbC05OTU1Nzc1\nMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAx2HI6ri2hhgrdkBvLz3YJ1InOY3gQsbT/s/wtCw1dE9dmZnsurPSUPGZsf9Cof8WoIvq\nTPpTDjS0g4wx0mVjY6qejmVF4OFUCHrJPDNvO0Mey2cfK4tCBtvFtnUsntl1c2HCfdi/mMNVV3Di\nTATlWeCMf++HBHE65HKO8B+PCRHbt2jYYT1CtBGGk9yFP4SN0iBAFE+az5QAf86iW2ZYuUmkt87G\nYxBSuwj9h1rW9g6yr2sDX+9cXBPB4/4nq5lKBzaAt/O+UMXBoMiWP2xh+KyyccOv13xtDJpBhZDH\nEVQp5X10I1bm5/Y8QpXG9qEd1C6pa76w4VoPernnYYRa9QIDAQABMA0GCSqGSIb3DQEBCwUAA4IB\nAQBrE+qga2ZbF99L3wa0oy9sfSq9/6B6E8KODNeYOZ6OCTXij8EMcKYZGRXV22qHr7AwA0MVfYi5\ntt5jAuHTnKBPHaoYzYjQlu7/QXbte8WoximdliQraiD/zAps61Qj+c1Pctt1dwH3xu2Ppx0P3KvL\nBNE/LDMSADNpTL/o0jQnOzH9KP47iCI8lzdboHtegXuAnlCLj3uSYFy/W4KPm1FZHjZFkmmZz0SH\n/W2tTtkPfeSC+c0G8IhhUHLJ2QUEmH4Sk+l4PM5Jklb4RnABUKfiuel1zKlBE5hpWcn4cYWrHwCl\n1NKiHj2mkWIwVey813T/7M+nk93WK1G6psCleczN"
]
}
]
}
]
}
],
"saml2:Subject": [
{
"$": {
"xmlns:saml2": "urn:oasis:names:tc:SAML:2.0:assertion"
},
"saml2:NameID": [
{
"_": "simon.larsen@oneuptime.com",
"$": {
"Format": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
}
}
],
"saml2:SubjectConfirmation": [
{
"$": {
"Method": "urn:oasis:names:tc:SAML:2.0:cm:bearer"
},
"saml2:SubjectConfirmationData": [
{
"$": {
"NotOnOrAfter": "2023-03-05T17:49:26.809Z",
"Recipient": "http://localhost/identity/idp-login/19462af5-a3c5-414d-bef8-20681c708579/56489843-5440-4305-a46a-c64215451b65"
}
}
]
}
]
}
],
"saml2:Conditions": [
{
"$": {
"NotBefore": "2023-03-05T17:39:26.809Z",
"NotOnOrAfter": "2023-03-05T17:49:26.809Z",
"xmlns:saml2": "urn:oasis:names:tc:SAML:2.0:assertion"
},
"saml2:AudienceRestriction": [
{
"saml2:Audience": [
"oneuptime-org-test"
]
}
]
}
],
"saml2:AuthnStatement": [
{
"$": {
"AuthnInstant": "2023-03-05T17:04:56.046Z",
"SessionIndex": "id1678038266807.2057378521",
"xmlns:saml2": "urn:oasis:names:tc:SAML:2.0:assertion"
},
"saml2:AuthnContext": [
{
"saml2:AuthnContextClassRef": [
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
]
}
]
}
]
}
]
}
}

View File

@@ -1,110 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response Destination="http://localhost/identity/idp-login/19462af5-a3c5-414d-bef8-20681c708579/56489843-5440-4305-a46a-c64215451b65" ID="id393052211033737791644147" IssueInstant="2023-03-05T19:34:15.185Z" Version="2.0"
xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exk4fi36tv3SJZtRv697
</saml2:Issuer>
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id393052211033737791644147">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>r0iRM7DfiX6Kbmd7ecNjNzfveJzMAbdtldt/J/XcBh4=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>qo7/aSP6ZzgK30+mLJLdyADwALofCP53YGoW4ALagLegkUBkCjakr7pfTdxGjVB9wGLiEs+AYwurTgnqr90g04AdSkEYlFVqORBMQqd/0qR0ZE64TeoDcioF7nLH/71v88fdBGugv5i9YjJ1CGuSeA6rh+pFfJbLsTH9Ktaur3VcEKIY14RGQHFHYeXabBffNb2AQBhMVzgxTSmNIAT5fiaUTTgfw4oe+kNyVtY8jKrPxEqi9IYM4xiF6BhQDt79AZnwp1Acqof6iXyH5fCNufuv8SjEZyOSIMFOqbLyWIIlqini1UwF1jLlD+HvbZH3+rb2fIcFuVmcqD7KzOHU8g==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDqjCCApKgAwIBAgIGAYao8ch8MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFjAUBgNVBAMMDXRyaWFsLTk5NTU3NzUxHDAaBgkqhkiG9w0B
CQEWDWluZm9Ab2t0YS5jb20wHhcNMjMwMzAzMTkyNjQzWhcNMzMwMzAzMTkyNzQzWjCBlTELMAkG
A1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTAL
BgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRYwFAYDVQQDDA10cmlhbC05OTU1Nzc1
MRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAx2HI6ri2hhgrdkBvLz3YJ1InOY3gQsbT/s/wtCw1dE9dmZnsurPSUPGZsf9Cof8WoIvq
TPpTDjS0g4wx0mVjY6qejmVF4OFUCHrJPDNvO0Mey2cfK4tCBtvFtnUsntl1c2HCfdi/mMNVV3Di
TATlWeCMf++HBHE65HKO8B+PCRHbt2jYYT1CtBGGk9yFP4SN0iBAFE+az5QAf86iW2ZYuUmkt87G
YxBSuwj9h1rW9g6yr2sDX+9cXBPB4/4nq5lKBzaAt/O+UMXBoMiWP2xh+KyyccOv13xtDJpBhZDH
EVQp5X10I1bm5/Y8QpXG9qEd1C6pa76w4VoPernnYYRa9QIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQBrE+qga2ZbF99L3wa0oy9sfSq9/6B6E8KODNeYOZ6OCTXij8EMcKYZGRXV22qHr7AwA0MVfYi5
tt5jAuHTnKBPHaoYzYjQlu7/QXbte8WoximdliQraiD/zAps61Qj+c1Pctt1dwH3xu2Ppx0P3KvL
BNE/LDMSADNpTL/o0jQnOzH9KP47iCI8lzdboHtegXuAnlCLj3uSYFy/W4KPm1FZHjZFkmmZz0SH
/W2tTtkPfeSC+c0G8IhhUHLJ2QUEmH4Sk+l4PM5Jklb4RnABUKfiuel1zKlBE5hpWcn4cYWrHwCl
1NKiHj2mkWIwVey813T/7M+nk93WK1G6psCleczN</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status
xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion ID="id393052211179439228346088" IssueInstant="2023-03-05T19:34:15.185Z" Version="2.0"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exk4fi36tv3SJZtRv697
</saml2:Issuer>
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id393052211179439228346088">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>q58zNeULspCtjaeoJW4HFDrU1sbJDTBYB7jFvxTfBGI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>Nhqd6JCCyLDkiDRFwXz8Y6nbTwb0CpH0SPYszpU6pvLTGMwU6jMiVuqhMFORUlb+wir/hgWLxS/dzv0QgudT/fMZ3FtjuC3TRYQJJaJHsC+rdhOBVdp4M0jZefSlSzFNyY9QC75QVkw1NsPe73pS6ldZ3f+Zx6QjKrXe+wUG6/5aBziQ+mVFA8I1URWAW767Uf3UazPsclYMirrt1mcsQHXQErlCg+Hf8adaZ1MLa5NfTLYucyXJiZKVg7gt8sXbB+2MgfboAVZS651Y/68v/zhR4EtZzanseaG9ICpm+fqUPkZ9r43xIlaHliTDrnScmrYM2PRX0iVsYNOLnhkXMQ==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDqjCCApKgAwIBAgIGAYao8ch8MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFjAUBgNVBAMMDXRyaWFsLTk5NTU3NzUxHDAaBgkqhkiG9w0B
CQEWDWluZm9Ab2t0YS5jb20wHhcNMjMwMzAzMTkyNjQzWhcNMzMwMzAzMTkyNzQzWjCBlTELMAkG
A1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTAL
BgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRYwFAYDVQQDDA10cmlhbC05OTU1Nzc1
MRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAx2HI6ri2hhgrdkBvLz3YJ1InOY3gQsbT/s/wtCw1dE9dmZnsurPSUPGZsf9Cof8WoIvq
TPpTDjS0g4wx0mVjY6qejmVF4OFUCHrJPDNvO0Mey2cfK4tCBtvFtnUsntl1c2HCfdi/mMNVV3Di
TATlWeCMf++HBHE65HKO8B+PCRHbt2jYYT1CtBGGk9yFP4SN0iBAFE+az5QAf86iW2ZYuUmkt87G
YxBSuwj9h1rW9g6yr2sDX+9cXBPB4/4nq5lKBzaAt/O+UMXBoMiWP2xh+KyyccOv13xtDJpBhZDH
EVQp5X10I1bm5/Y8QpXG9qEd1C6pa76w4VoPernnYYRa9QIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQBrE+qga2ZbF99L3wa0oy9sfSq9/6B6E8KODNeYOZ6OCTXij8EMcKYZGRXV22qHr7AwA0MVfYi5
tt5jAuHTnKBPHaoYzYjQlu7/QXbte8WoximdliQraiD/zAps61Qj+c1Pctt1dwH3xu2Ppx0P3KvL
BNE/LDMSADNpTL/o0jQnOzH9KP47iCI8lzdboHtegXuAnlCLj3uSYFy/W4KPm1FZHjZFkmmZz0SH
/W2tTtkPfeSC+c0G8IhhUHLJ2QUEmH4Sk+l4PM5Jklb4RnABUKfiuel1zKlBE5hpWcn4cYWrHwCl
1NKiHj2mkWIwVey813T/7M+nk93WK1G6psCleczN</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">simon.larsen@oneuptime.com</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData NotOnOrAfter="2023-03-05T19:39:15.185Z" Recipient="http://localhost/identity/idp-login/19462af5-a3c5-414d-bef8-20681c708579/56489843-5440-4305-a46a-c64215451b65"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2023-03-05T19:29:15.185Z" NotOnOrAfter="2023-03-05T19:39:15.185Z"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:AudienceRestriction>
<saml2:Audience>oneuptime-org-test</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2023-03-05T18:45:10.375Z" SessionIndex="id1678044855184.109954533"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
</saml2:Assertion>
</saml2p:Response>

View File

@@ -1,57 +0,0 @@
import 'ejs';
import { PostgresAppInstance } from 'CommonServer/Infrastructure/PostgresDatabase';
import Express, { ExpressApplication } from 'CommonServer/Utils/Express';
import logger from 'CommonServer/Utils/Logger';
import App from 'CommonServer/Utils/StartServer';
import AuthenticationAPI from './API/Authentication';
import SsoAPI from './API/SSO';
import ResellerAPI from './API/Reseller';
import StatusPageSsoAPI from './API/StatusPageSSO';
import StatusPageAuthenticationAPI from './API/StatusPageAuthentication';
import Redis from 'CommonServer/Infrastructure/Redis';
import { ClickhouseAppInstance } from 'CommonServer/Infrastructure/ClickhouseDatabase';
const app: ExpressApplication = Express.getExpressApp();
const APP_NAME: string = 'identity';
app.use([`/${APP_NAME}`, '/'], AuthenticationAPI);
app.use([`/${APP_NAME}`, '/'], ResellerAPI);
app.use([`/${APP_NAME}`, '/'], SsoAPI);
app.use([`/${APP_NAME}`, '/'], StatusPageSsoAPI);
app.use(
[`/${APP_NAME}/status-page`, '/status-page'],
StatusPageAuthenticationAPI
);
const init: () => Promise<void> = async (): Promise<void> => {
try {
// init the app
await App(APP_NAME);
// connect to the database.
await PostgresAppInstance.connect(
PostgresAppInstance.getDatasourceOptions()
);
// connect redis
await Redis.connect();
await ClickhouseAppInstance.connect(
ClickhouseAppInstance.getDatasourceOptions()
);
} catch (err) {
logger.error('App Init Failed:');
logger.error(err);
throw err;
}
};
init().catch((err: Error) => {
logger.error(err);
logger.info('Exiting node process');
process.exit(1);
});

View File

@@ -1,62 +0,0 @@
import { AccountsRoute } from 'Common/ServiceRoute';
import EmailVerificationTokenService from 'CommonServer/Services/EmailVerificationTokenService';
import ObjectID from 'Common/Types/ObjectID';
import EmailVerificationToken from 'Model/Models/EmailVerificationToken';
import MailService from 'CommonServer/Services/MailService';
import EmailTemplateType from 'Common/Types/Email/EmailTemplateType';
import URL from 'Common/Types/API/URL';
import OneUptimeDate from 'Common/Types/Date';
import Route from 'Common/Types/API/Route';
import logger from 'CommonServer/Utils/Logger';
import User from 'Model/Models/User';
import Hostname from 'Common/Types/API/Hostname';
import Protocol from 'Common/Types/API/Protocol';
import Email from 'Common/Types/Email';
import DatabaseConfig from 'CommonServer/DatabaseConfig';
export default class AuthenticationEmail {
public static async sendVerificationEmail(user: User): Promise<void> {
const generatedToken: ObjectID = ObjectID.generate();
const emailVerificationToken: EmailVerificationToken =
new EmailVerificationToken();
emailVerificationToken.userId = user?.id as ObjectID;
emailVerificationToken.email = user?.email as Email;
emailVerificationToken.token = generatedToken;
emailVerificationToken.expires = OneUptimeDate.getOneDayAfter();
await EmailVerificationTokenService.create({
data: emailVerificationToken,
props: {
isRoot: true,
},
});
const host: Hostname = await DatabaseConfig.getHost();
const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
MailService.sendMail({
toEmail: user.email!,
subject: 'Please verify email.',
templateType: EmailTemplateType.SignupWelcomeEmail,
vars: {
name: user.name?.toString() || '',
tokenVerifyUrl: new URL(
httpProtocol,
host,
new Route(AccountsRoute.toString()).addRoute(
'/verify-email/' + generatedToken.toString()
)
).toString(),
homeUrl: new URL(httpProtocol, host).toString(),
},
}).catch((err: Error) => {
logger.error(err);
});
}
}

View File

@@ -1,193 +0,0 @@
import { JSONArray, JSONObject } from 'Common/Types/JSON';
import BadRequestException from 'Common/Types/Exception/BadRequestException';
import Email from 'Common/Types/Email';
import xmldom from 'xmldom';
import xmlCrypto, { FileKeyInfo } from 'xml-crypto';
import logger from 'CommonServer/Utils/Logger';
export default class SSOUtil {
public static isPayloadValid(payload: JSONObject): void {
if (
!payload['saml2p:Response'] &&
!payload['samlp:Response'] &&
!payload['samlp:Response']
) {
throw new BadRequestException('SAML Response not found.');
}
payload =
(payload['saml2p:Response'] as JSONObject) ||
(payload['samlp:Response'] as JSONObject) ||
(payload['samlp:Response'] as JSONObject);
const issuers: JSONArray =
(payload['saml2:Issuer'] as JSONArray) ||
(payload['saml:Issuer'] as JSONArray);
if (issuers.length === 0) {
throw new BadRequestException('Issuers not found');
}
const issuer: JSONObject | string | undefined = issuers[0];
if (typeof issuer === 'string') {
return issuer;
}
if (!issuer) {
throw new BadRequestException('Issuer not found');
}
const issuerUrl: string = issuer['_'] as string;
if (!issuerUrl) {
throw new BadRequestException(
'Issuer URL not found in SAML response'
);
}
const samlAssertion: JSONArray =
(payload['saml2:Assertion'] as JSONArray) ||
(payload['saml:Assertion'] as JSONArray);
if (!samlAssertion || samlAssertion.length === 0) {
throw new BadRequestException('SAML Assertion not found');
}
const samlSubject: JSONArray =
((samlAssertion[0] as JSONObject)['saml2:Subject'] as JSONArray) ||
((samlAssertion[0] as JSONObject)['saml:Subject'] as JSONArray);
if (!samlSubject || samlSubject.length === 0) {
throw new BadRequestException('SAML Subject not found');
}
const samlNameId: JSONArray =
((samlSubject[0] as JSONObject)['saml2:NameID'] as JSONArray) ||
((samlSubject[0] as JSONObject)['saml:NameID'] as JSONArray);
if (!samlNameId || samlNameId.length === 0) {
throw new BadRequestException('SAML NAME ID not found');
}
const emailString: string = (samlNameId[0] as JSONObject)[
'_'
] as string;
if (!emailString) {
if (!samlNameId || samlNameId.length === 0) {
throw new BadRequestException('SAML Email not found');
}
}
}
public static isSignatureValid(
samlPayload: string,
certificate: string
): boolean {
try {
const dom: Document = new xmldom.DOMParser().parseFromString(
samlPayload
);
const signature: Element | undefined = dom.getElementsByTagNameNS(
'http://www.w3.org/2000/09/xmldsig#',
'Signature'
)[0];
const sig: xmlCrypto.SignedXml = new xmlCrypto.SignedXml();
sig.keyInfoProvider = {
getKeyInfo: function (_key: any) {
return `<X509Data><X509Certificate>${certificate}</X509Certificate></X509Data>`;
},
getKey: function () {
return certificate;
} as any,
} as FileKeyInfo;
sig.loadSignature(signature!.toString());
const res: boolean = sig.checkSignature(samlPayload);
return res;
} catch (err) {
logger.error(err);
return false;
}
}
public static getEmail(payload: JSONObject): Email {
if (!payload['saml2p:Response'] && !payload['samlp:Response']) {
throw new BadRequestException('SAML Response not found.');
}
payload =
(payload['saml2p:Response'] as JSONObject) ||
(payload['samlp:Response'] as JSONObject);
const samlAssertion: JSONArray =
(payload['saml2:Assertion'] as JSONArray) ||
(payload['saml:Assertion'] as JSONArray);
if (!samlAssertion || samlAssertion.length === 0) {
throw new BadRequestException('SAML Assertion not found');
}
const samlSubject: JSONArray =
((samlAssertion[0] as JSONObject)['saml2:Subject'] as JSONArray) ||
((samlAssertion[0] as JSONObject)['saml:Subject'] as JSONArray);
if (!samlSubject || samlSubject.length === 0) {
throw new BadRequestException('SAML Subject not found');
}
const samlNameId: JSONArray =
((samlSubject[0] as JSONObject)['saml2:NameID'] as JSONArray) ||
((samlSubject[0] as JSONObject)['saml:NameID'] as JSONArray);
if (!samlNameId || samlNameId.length === 0) {
throw new BadRequestException('SAML NAME ID not found');
}
const emailString: string = (samlNameId[0] as JSONObject)[
'_'
] as string;
return new Email(emailString.trim());
}
public static getIssuer(payload: JSONObject): string {
if (!payload['saml2p:Response'] && !payload['samlp:Response']) {
throw new BadRequestException('SAML Response not found.');
}
payload =
(payload['saml2p:Response'] as JSONObject) ||
(payload['samlp:Response'] as JSONObject);
const issuers: JSONArray =
(payload['saml2:Issuer'] as JSONArray) ||
(payload['saml:Issuer'] as JSONArray);
if (issuers.length === 0) {
throw new BadRequestException('Issuers not found');
}
const issuer: JSONObject | string | undefined = issuers[0];
if (typeof issuer === 'string') {
return issuer;
}
if (!issuer) {
throw new BadRequestException('Issuer not found');
}
const issuerUrl: string = issuer['_'] as string;
if (!issuerUrl) {
throw new BadRequestException(
'Issuer URL not found in SAML response'
);
}
return issuerUrl.trim();
}
}

View File

@@ -1,51 +0,0 @@
<html>
<head>
<%- include('./Partials/Head.ejs') -%>
<title> <%= title %> </title>
</head>
<body class="bg-gray-100">
<div class="h-full">
<main class="mx-auto max-w-7xl pb-10 lg:py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-md flex justify-center mt-10 mb-10">
<img
class="mx-auto h-12 w-auto"
src="/img/3-transparent.svg"
alt="OneUptime"
/>
</div>
<div class="">
<!-- Payment details -->
<div class="space-y-6 sm:px-6 lg:col-span-9 lg:px-0">
<section aria-labelledby="payment-details-heading">
<form action="#" method="POST">
<div class="shadow sm:overflow-hidden sm:rounded-md">
<div class="bg-white py-6 px-4 sm:p-6">
<div>
<h2 id="payment-details-heading"
class="text-lg font-medium leading-6 text-gray-900"><%= title %></h2>
<p class="mt-1 text-sm text-gray-500"><%= message %></p>
</div>
</div>
</div>
</form>
</section>
</div>
</div>
</main>
</div>
</body>
</html>

View File

@@ -1,103 +0,0 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"
rel="stylesheet">
<style>
* {
font-family: Inter;
}
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
background: transparent;
bottom: 0;
color: transparent;
cursor: pointer;
height: auto;
left: 0;
position: absolute;
right: 0;
top: 0;
width: auto;
}
input[type="date"]::-webkit-calendar-picker-indicator {
background: transparent;
bottom: 0;
color: transparent;
cursor: pointer;
height: auto;
left: 0;
position: absolute;
right: 0;
top: 0;
width: auto;
}
</style>
<script src="https://cdn.tailwindcss.com"></script>
<!-- Google Tag Manager -->
<script>(function (w, d, s, l, i) {
w[l] = w[l] || []; w[l].push({
'gtm.start':
new Date().getTime(), event: 'gtm.js'
}); var f = d.getElementsByTagName(s)[0],
j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-PKQD5WH');</script>
<!-- End Google Tag Manager -->
<style>
.async-hide {
opacity: 0 !important
}
</style>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="/img/favicons/favicon.ico">
<link rel="apple-touch-icon" sizes="180x180" href="/img/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicons/favicon-16x16.png">
<link rel="mask-icon" href="/img/favicons/safari-pinned-tab.svg" color="#32335b">
<meta name="msapplication-TileColor" content="#32335b">
<link rel="apple-touch-icon-precomposed" href="/img/ou-wb.svg">
<link rel="icon" href="/img/ou-wb.svg">
<link rel="image_src" type="image/png" href="/img/hou-wb.svg">
<link rel="canonical" href="/">
<link rel="manifest" href="/manifest.json">
<meta property="og:title" content="OneUptime - One Complete Observability platform.">
<meta property="og:url" content="https://oneuptime.com">
<meta property="og:type" content="website" />
<meta property="og:description"
content="OneUptime monitors websites, API's, and servers and alerts your team if something goes wrong. It also keeps your customers updated about any downtime. ">
<meta property="og:image" content="https://oneuptime.com/img/hou-wb.svg">
<meta name="twitter:card" content="summary">
<meta name="theme-color" content="#000000">
<meta name="twitter:image" content="/img/ou-wb.svg">
<meta name="twitter:site" content="@oneuptimeinc">
<meta name="twitter:title" content="OneUptime - One Complete Observability platform.">
<meta name="twitter:description"
content="OneUptime monitors websites, API's, and servers and alerts your team if something goes wrong. It also keeps your customers updated about any downtime.">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Corporation",
"name": "OneUptime",
"url": "https://www.oneuptime.com",
"logo": "https://oneuptime.com/img/ou-bb.svg",
"sameAs": [
"https://www.facebook.com/oneuptimeinc",
"https://twitter.com/OneUptimeInc",
"https://www.linkedin.com/company/oneuptime"
],
"description": "OneUptime monitors websites, API's, and servers and alerts your team if something goes wrong. It also keeps your customers updated about any downtime."
}
</script>

View File

@@ -1,5 +0,0 @@
{
"watch": ["./","../Common", "../CommonServer", "../Model"],
"ext": "ts,json,tsx,env,js,jsx,hbs",
"exec": "node --inspect=0.0.0.0:9229 --require ts-node/register Index.ts"
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +0,0 @@
{
"name": "identity",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node --require ts-node/register Index.ts",
"compile": "tsc",
"clear-modules": "rm -rf node_modules && rm package-lock.json && npm install",
"dev": "npx nodemon",
"audit": "npm audit --audit-level=low",
"dep-check": "npm install -g depcheck && depcheck ./ --skip-missing=true",
"test": "jest --detectOpenHandles",
"coverage": "jest --detectOpenHandles --coverage"
},
"author": "",
"license": "ISC",
"dependencies": {
"Common": "file:../Common",
"CommonServer": "file:../CommonServer",
"ejs": "^3.1.9",
"Model": "file:../Model",
"ts-node": "^10.9.1",
"xml-crypto": "^3.2.0",
"xml2js": "^0.6.2",
"xmldom": "^0.6.0"
},
"devDependencies": {
"@types/xml-crypto": "^1.4.5",
"@types/xml2js": "^0.4.14",
"@types/xmldom": "^0.1.34",
"@types/node": "^17.0.31",
"jest": "^28.1.0",
"nodemon": "^2.0.20"
}
}

View File

@@ -1,112 +0,0 @@
{
"ts-node": {
// these options are overrides used only by ts-node
// same as the --compilerOptions flag and the TS_NODE_COMPILER_OPTIONS environment variable
"compilerOptions": {
"module": "commonjs"
}
},
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "react" /* Specify what JSX code is generated. */,
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
// "module": "es2022" /* Specify what module code is generated. */,
"rootDir": "", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types"
], /* Specify multiple folders that act like `./node_modules/@types`. */
"types": ["node"], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
"outDir": "build/dist", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
"strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
"strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
"strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
"strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
"noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
"useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
"alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
"noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
"noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
"exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
"noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
"noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
"noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -2,9 +2,6 @@ upstream accounts {
server ${SERVER_ACCOUNTS_HOSTNAME}:${ACCOUNTS_PORT} weight=10 max_fails=3 fail_timeout=30s;
}
upstream identity {
server ${SERVER_IDENTITY_HOSTNAME}:${IDENTITY_PORT} weight=10 max_fails=3 fail_timeout=30s;
}
upstream dashboard-api {
server ${SERVER_DASHBOARD_API_HOSTNAME}:${DASHBOARD_API_PORT} weight=10 max_fails=3 fail_timeout=30s;
@@ -102,7 +99,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity/status-page-sso/;
proxy_pass http://dashboard-api/api/identity/status-page-sso/;
}
location /status-page-identity-api/ {
@@ -116,7 +113,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity/status-page/;
proxy_pass http://dashboard-api/api/identity/status-page/;
}
# Acme Verification.
@@ -200,7 +197,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity/status-page-sso/;
proxy_pass http://dashboard-api/api/identity/status-page-sso/;
}
location /status-page-identity-api/ {
@@ -214,7 +211,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity/status-page/;
proxy_pass http://dashboard-api/api/identity/status-page/;
}
location /status-page {
@@ -300,7 +297,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity/status-page-sso/;
proxy_pass http://dashboard-api/api/identity/status-page-sso/;
}
location /status-page-identity-api/ {
@@ -314,7 +311,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity/status-page/;
proxy_pass http://dashboard-api/api/identity/status-page/;
}
@@ -423,7 +420,7 @@ server {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://identity;
proxy_pass http://dashboard-api/api/identity;
}
location /reference {

View File

@@ -81,9 +81,7 @@ SERVER_WORKFLOW_HOSTNAME=workflow
SERVER_ALERT_HOSTNAME=alert
SERVER_INGESTOR_HOSTNAME=ingestor
SERVER_TEST_SERVER_HOSTNAME=test-server
SERVER_FILE_HOSTNAME=file
SERVER_HOME_HOSTNAME=home
SERVER_IDENTITY_HOSTNAME=identity
SERVER_NOTIFICATION_HOSTNAME=hostname
SERVER_WORKERS_HOSTNAME=workers
SERVER_STATUS_PAGE_HOSTNAME=status-page
@@ -101,9 +99,7 @@ ALERT_PORT=3088
INGESTOR_PORT=3400
PROBE_PORT=3500
TEST_SERVER_PORT=3800
FILE_PORT=3125
HOME_PORT=1444
IDENTITY_PORT=3087
NOTIFICATION_PORT=3191
REALTIME_PORT=3300
WORKERS_PORT=3452

View File

@@ -23,9 +23,7 @@ x-common-variables: &common-variables
SERVER_ALERT_HOSTNAME: alert
SERVER_INGESTOR_HOSTNAME: ingestor
SERVER_TEST_SERVER_HOSTNAME: test-server
SERVER_FILE_HOSTNAME: file
SERVER_HOME_HOSTNAME: home
SERVER_IDENTITY_HOSTNAME: identity
SERVER_NOTIFICATION_HOSTNAME: notification
SERVER_WORKERS_HOSTNAME: workers
SERVER_STATUS_PAGE_HOSTNAME: status-page
@@ -43,9 +41,7 @@ x-common-variables: &common-variables
INGESTOR_PORT: ${INGESTOR_PORT}
PROBE_PORT: ${PROBE_PORT}
TEST_SERVER_PORT: ${TEST_SERVER_PORT}
FILE_PORT: ${FILE_PORT}
HOME_PORT: ${HOME_PORT}
IDENTITY_PORT: ${IDENTITY_PORT}
NOTIFICATION_PORT: ${NOTIFICATION_PORT}
REALTIME_PORT: ${REALTIME_PORT}
WORKERS_PORT: ${WORKERS_PORT}
@@ -173,8 +169,6 @@ services:
environment:
<<: *common-ui-variables
PORT: ${ACCOUNTS_PORT}
depends_on:
- identity
admin-dashboard:
@@ -184,9 +178,6 @@ services:
environment:
<<: *common-ui-variables
PORT: ${ADMIN_DASHBOARD_PORT}
depends_on:
- identity
- accounts
dashboard:
networks:
@@ -195,9 +186,6 @@ services:
environment:
<<: *common-ui-variables
PORT: ${DASHBOARD_PORT}
depends_on:
- identity
- accounts
@@ -312,23 +300,6 @@ services:
- ingestor
links:
- ingestor
identity:
networks:
- oneuptime
restart: always
environment:
<<: *common-server-variables
PORT: ${IDENTITY_PORT}
depends_on:
- redis
- postgres
- notification
links:
- redis
- postgres
- notification
otel-collector:
@@ -378,7 +349,6 @@ services:
ingress:
depends_on:
- identity
- accounts
- dashboard-api
- dashboard

View File

@@ -297,34 +297,7 @@ services:
network: host
context: .
dockerfile: ./Probe/Dockerfile
identity:
ports:
- '9132:9229' # Debugging port.
volumes:
- ./Identity:/usr/src/app
# Use node modules of the container and not host system.
# https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder
- /usr/src/app/node_modules/
- ./Common:/usr/src/Common
- ./Model:/usr/src/Model
- ./CommonServer:/usr/src/CommonServer
- ./CommonUI:/usr/src/CommonUI
- /usr/src/Common/node_modules/
- /usr/src/CommonUI/node_modules/
- /usr/src/CommonServer/node_modules/
- /usr/src/Model/node_modules/
extends:
file: ./docker-compose.base.yml
service: identity
build:
network: host
context: .
dockerfile: ./Identity/Dockerfile
ingestor:
volumes:
- ./Ingestor:/usr/src/app

View File

@@ -100,14 +100,6 @@ services:
file: ./docker-compose.base.yml
service: probe-2
identity:
image: oneuptime/identity:${APP_TAG}
extends:
file: ./docker-compose.base.yml
service: identity
ingestor:
image: oneuptime/ingestor:${APP_TAG}
extends: