Skip to content

Commit

Permalink
Feat: Access APIs with token (#116)
Browse files Browse the repository at this point in the history
* Feat: added way to add custom integrations and added api key facility

* Feat: added way to add custom integrations and added api key facility
  • Loading branch information
harshithmullapudi authored Jun 29, 2023
1 parent d451798 commit 7b0ddf7
Show file tree
Hide file tree
Showing 81 changed files with 927 additions and 173 deletions.
4 changes: 2 additions & 2 deletions engine-edk/src/common_models/ticketing/ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ export interface Ticket {
export interface CreateTicketBody {
name: string;
description: string;
assignees: Assignee[];
assignees: Exclude<Assignee, 'username'>[];
tags: Tag[];
}

export interface UpdateTicketBody {
name: string;
description: string;
assignees: Assignee[];
assignees: Exclude<Assignee, 'username'>[];
tags: Tag[];
status: string;
}
1 change: 1 addition & 0 deletions engine-server/prisma/dbml/schema.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Table IntegrationDefinition {
name String [not null]
key String [not null]
icon String
version String [not null, default: '0.0.1']
releaseStage ReleaseStage [not null, default: 'ALPHA']
sourceUrl String [not null]
integrationType IntegrationType [not null]
Expand Down
2 changes: 2 additions & 0 deletions engine-server/prisma/migrations/20230629062746_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "IntegrationDefinition" ADD COLUMN "version" TEXT NOT NULL DEFAULT '0.0.1';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- This is an empty migration.
1 change: 1 addition & 0 deletions engine-server/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ model IntegrationDefinition {
name String
key String
icon String?
version String @default("0.0.1")
releaseStage ReleaseStage @default(ALPHA)
sourceUrl String
integrationType IntegrationType
Expand Down
29 changes: 14 additions & 15 deletions engine-server/prisma/seeds/extension_definition.seed.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import {
IntegrationType,
PrismaClient,
ReleaseStage,
} from '@prisma/client';
/** Copyright (c) 2023, Poozle, all rights reserved. **/

import { IntegrationType, PrismaClient, ReleaseStage } from '@prisma/client';
// import axios from 'axios';

const prisma = new PrismaClient();

type IntegrationDefinitions = {
[key: string]: {
name: string;
key: string;
icon: string;
sourceUrl: string;
releaseStage: string;
integrationType: string;
};
};
type IntegrationDefinitions = Record<
string,
{
name: string;
key: string;
icon: string;
sourceUrl: string;
releaseStage: string;
integrationType: string;
}
>;

async function main() {
const integrationDefinitions = await prisma.integrationDefinition.findMany({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@

import {IntegrationType} from '@prisma/client'
import {Workspace} from '../../workspace/entities/workspace.entity'
import {IntegrationAccount} from '../../integrationAccount/entities/integrationAccount.entity'


export class IntegrationConnectLink {
integrationConnectionLinkId: string ;
expiresIn: number ;
category: IntegrationType[] ;
workspace?: Workspace ;
workspaceId: string ;
createdAt: Date ;
updatedAt: Date ;
IntegrationAccount?: IntegrationAccount[] ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export class IntegrationDefinition {
name: string ;
key: string ;
icon: string | null;
version: string ;
releaseStage: ReleaseStage ;
sourceUrl: string ;
integrationType: IntegrationType ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {User} from '../../user/entities/user.entity'
import {IntegrationDefinition} from '../../integrationDefinition/entities/integrationDefinition.entity'
import {IntegrationAccount} from '../../integrationAccount/entities/integrationAccount.entity'
import {IntegrationOAuthApp} from '../../integrationOAuthApp/entities/integrationOAuthApp.entity'
import {IntegrationConnectLink} from '../../integrationConnectLink/entities/integrationConnectLink.entity'


export class Workspace {
Expand All @@ -16,4 +17,5 @@ IntegrationDefinition?: IntegrationDefinition[] ;
IntegrationAccount?: IntegrationAccount[] ;
IntegrationOAuthApp?: IntegrationOAuthApp[] ;
deleted: Date | null;
IntegrationConnectLink?: IntegrationConnectLink[] ;
}
80 changes: 68 additions & 12 deletions engine-server/src/modules/auth/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
/** Copyright (c) 2023, Poozle, all rights reserved. **/

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { verify, decode } from 'jsonwebtoken';
import { JwksClient } from 'jwks-rsa';
import { Error as STError } from 'supertokens-node';
import Session from 'supertokens-node/recipe/session';
import { VerifySessionOptions } from 'supertokens-node/recipe/session';
import { verifySession } from 'supertokens-node/recipe/session/framework/express';

async function getKey(jwt: string) {
const decoded = decode(jwt, { complete: true });

const client = new JwksClient({
jwksUri: `${process.env.BACKEND_HOST}/auth/jwt/jwks.json`,
});

const key = await client.getSigningKey(decoded.header.kid);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return key!.getPublicKey();
}

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly verifyOptions?: VerifySessionOptions) {}
Expand All @@ -14,19 +34,55 @@ export class AuthGuard implements CanActivate {

let err = undefined;
const resp = ctx.getResponse();
// You can create an optional version of this by passing {sessionRequired: false} to verifySession
await verifySession(this.verifyOptions)(ctx.getRequest(), resp, (res) => {
err = res;
});

if (resp.headersSent) {
throw new STError({
message: 'RESPONSE_SENT',
type: 'RESPONSE_SENT',
const request = ctx.getRequest();
try {
const session = await Session.getSession(request, resp, {
sessionRequired: false,
});
}

if (err) {
if (session !== undefined) {
// API call from the frontend and session verification is successful..
await verifySession({ ...this.verifyOptions })(request, resp, (res) => {
err = res;
});
} else {
// this for users to call from their APIs
let jwt = request.headers['authorization'];
jwt = jwt === undefined ? undefined : jwt.split('Bearer ')[1];
if (jwt === undefined) {
throw new UnauthorizedException({
message: 'unauthorised',
});
} else {
const publicKey = await getKey(jwt);

try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response: any = verify(jwt, publicKey, {});
if (response.source !== 'microservice') {
throw new UnauthorizedException({
message: 'unauthorised',
});
}
} catch (e) {
throw new UnauthorizedException({
message: 'unauthorised',
});
}
}
}

if (resp.headersSent) {
throw new STError({
message: 'RESPONSE_SENT',
type: 'RESPONSE_SENT',
});
}

if (err) {
throw err;
}
} catch (err) {
throw err;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** Copyright (c) 2023, Poozle, all rights reserved. **/
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,6 @@ export class Ticket {
tags: Tag[];
}

export class CreateTicketBody {
id: number;
parent_id: string;
collection_id: string;
type: string;
name: string;
description: string;
status: string;
priority: string;
ticket_url: string;
assignees: Assignee[];
updated_at: string;
created_at: string;
created_by: string;
due_date: string;
completed_at: string;
tags: Tag[];
}

export class TicketingTicketResponse {
data: Ticket;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ export class IntegrationAccountService {
async getIntegrationAccountWithIntegrationType(
integrationAccountRequestBody: IntegrationAccountRequestBodyWithIntegrationType,
) {
console.log(integrationAccountRequestBody);
const integrationAccounts =
await this.prismaService.integrationAccount.findMany({
where: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
/** Copyright (c) 2023, Poozle, all rights reserved. **/

import { Controller, Get, Param, Query, UseGuards } from '@nestjs/common';
import {
Body,
Controller,
Get,
Param,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Specification } from '@poozle/engine-edk';

import { IntegrationDefinition } from '@@generated/integrationDefinition/entities';

import { AuthGuard } from 'modules/auth/auth.guard';

import {
IntegrationDefinitionCreateBody,
IntegrationDefinitionRequestIdBody,
IntegrationDefinitionRequestWorkspaceIdBody,
} from './integration_definition.interface';
Expand Down Expand Up @@ -46,6 +57,16 @@ export class IntegrationDefinitionController {
);
}

@Post()
async createIntegrationDefinition(
@Body()
integrationDefinitionCreateBody: IntegrationDefinitionCreateBody,
): Promise<IntegrationDefinition> {
return await this.integrationDefinitionService.createIntegrationDefinition(
integrationDefinitionCreateBody,
);
}

@Get(':integrationDefinitionId')
async getIntegrationDefinitionWithId(
@Param()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** Copyright (c) 2023, Poozle, all rights reserved. **/

import { Specification } from '@poozle/engine-edk';
import { IntegrationType } from '@prisma/client';
import { IsString } from 'class-validator';

export class IntegrationDefinitionRequestWorkspaceIdBody {
Expand All @@ -16,3 +17,16 @@ export class IntegrationDefinitionRequestIdBody {
export class IntegrationDefinitionSpec {
spec: Specification;
}

export class IntegrationDefinitionCreateBody {
@IsString()
name: string;

@IsString()
sourceUrl: string;

integrationType: IntegrationType;

@IsString()
workspaceId: string;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
/* eslint-disable dot-location */
/** Copyright (c) 2023, Poozle, all rights reserved. **/

import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable } from '@nestjs/common';
import { Specification } from '@poozle/engine-edk';
import { ReleaseStage } from '@prisma/client';
import { PrismaService } from 'nestjs-prisma';
import { getIntegrationSpec } from 'shared/integration_run_utils';

import { IntegrationDefinition } from '@@generated/integrationDefinition/entities';

import {
IntegrationDefinitionCreateBody,
IntegrationDefinitionRequestIdBody,
IntegrationDefinitionRequestWorkspaceIdBody,
} from './integration_definition.interface';
Expand Down Expand Up @@ -70,4 +73,25 @@ export class IntegrationDefinitionService {

return await getIntegrationSpec(integrationDefinition.sourceUrl);
}

async createIntegrationDefinition(
integrationDefinitionCreateBody: IntegrationDefinitionCreateBody,
) {
try {
await getIntegrationSpec(integrationDefinitionCreateBody.sourceUrl);

return this.prisma.integrationDefinition.create({
data: {
...integrationDefinitionCreateBody,
key: integrationDefinitionCreateBody.name
.toLowerCase()
.replace(/ /g, '_'),
releaseStage: ReleaseStage.CUSTOM,
icon: 'custom.svg',
},
});
} catch (err) {
throw new BadRequestException('Unable to fetch spec');
}
}
}
Loading

0 comments on commit 7b0ddf7

Please sign in to comment.