Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ PUBLIC_APP_STORE_EID_WALLET=""
PUBLIC_PLAY_STORE_EID_WALLET=""
NOTIFICATION_SHARED_SECRET=your-notification-secret-key

PUBLIC_ESIGNER_BASE_URL="http://localhost:3004"

DREAMSYNC_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/dreamsync
VITE_DREAMSYNC_BASE_URL="http://localhost:8888"

Expand Down
48 changes: 48 additions & 0 deletions platforms/esigner-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "esigner-api",
"version": "1.0.0",
"description": "eSigner Document Signing Platform API",
"main": "src/index.ts",
"scripts": {
"start": "ts-node src/index.ts",
"dev": "nodemon --exec ts-node src/index.ts",
"build": "tsc && cp -r src/web3adapter/mappings dist/web3adapter/",
"typeorm": "typeorm-ts-node-commonjs",
"migration:generate": "npm run typeorm migration:generate -- -d src/database/data-source.ts",
"migration:run": "npm run typeorm migration:run -- -d src/database/data-source.ts",
"migration:revert": "npm run typeorm migration:revert -- -d src/database/data-source.ts"
},
"dependencies": {
"axios": "^1.6.7",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"eventsource-polyfill": "^0.9.6",
"express": "^4.18.2",
"graphql-request": "^6.1.0",
"jsonwebtoken": "^9.0.2",
"multer": "^1.4.5-lts.1",
"pg": "^8.11.3",
"reflect-metadata": "^0.2.1",
"typeorm": "^0.3.24",
"uuid": "^9.0.1",
"signature-validator": "workspace:*",
"web3-adapter": "workspace:*"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.5",
"@types/multer": "^1.4.11",
"@types/node": "^20.11.24",
"@types/pg": "^8.11.2",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.0.1",
"@typescript-eslint/parser": "^7.0.1",
"eslint": "^8.56.0",
"nodemon": "^3.0.3",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
}


134 changes: 134 additions & 0 deletions platforms/esigner-api/src/controllers/AuthController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { Request, Response } from "express";
import { v4 as uuidv4 } from "uuid";
import { UserService } from "../services/UserService";
import { EventEmitter } from "events";
import { signToken } from "../utils/jwt";
import { isVersionValid } from "../utils/version";
import { verifySignature } from "signature-validator";

const MIN_REQUIRED_VERSION = "0.4.0";

export class AuthController {
private userService: UserService;
private eventEmitter: EventEmitter;

constructor() {
this.userService = new UserService();
this.eventEmitter = new EventEmitter();
}

sseStream = async (req: Request, res: Response) => {
const { id } = req.params;

res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
"Access-Control-Allow-Origin": "*",
});

const handler = (data: any) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};

this.eventEmitter.on(id, handler);

req.on("close", () => {
this.eventEmitter.off(id, handler);
res.end();
});

req.on("error", (error) => {
console.error("SSE Error:", error);
this.eventEmitter.off(id, handler);
res.end();
});
};

getOffer = async (req: Request, res: Response) => {
const url = new URL(
"/api/auth",
process.env.PUBLIC_ESIGNER_BASE_URL,
).toString();
const session = uuidv4();
const offer = `w3ds://auth?redirect=${url}&session=${session}&platform=esigner`;
res.json({ uri: offer });
};

login = async (req: Request, res: Response) => {
try {
const { ename, session, appVersion, signature } = req.body;

if (!ename) {
return res.status(400).json({ error: "ename is required" });
}

if (!session) {
return res.status(400).json({ error: "session is required" });
}

if (!signature) {
return res.status(400).json({ error: "signature is required" });
}

if (!appVersion || !isVersionValid(appVersion, MIN_REQUIRED_VERSION)) {
const errorMessage = {
error: true,
message: `Your eID Wallet app version is outdated. Please update to version ${MIN_REQUIRED_VERSION} or later.`,
type: "version_mismatch"
};
this.eventEmitter.emit(session, errorMessage);
return res.status(400).json({
error: "App version too old",
message: errorMessage.message
});
}

const registryBaseUrl = process.env.PUBLIC_REGISTRY_URL;
if (!registryBaseUrl) {
console.error("PUBLIC_REGISTRY_URL not configured");
return res.status(500).json({ error: "Server configuration error" });
}

const verificationResult = await verifySignature({
eName: ename,
signature: signature,
payload: session,
registryBaseUrl: registryBaseUrl,
});

if (!verificationResult.valid) {
console.error("Signature validation failed:", verificationResult.error);
return res.status(401).json({
error: "Invalid signature",
message: verificationResult.error
});
}

let user = await this.userService.findByEname(ename);

if (!user) {
throw new Error("User not found");
}

const token = signToken({ userId: user.id });

const data = {
user: {
id: user.id,
ename: user.ename,
isVerified: user.isVerified,
isPrivate: user.isPrivate,
},
token,
};
this.eventEmitter.emit(session, data);
res.status(200).json(data);
} catch (error) {
console.error("Error during login:", error);
res.status(500).json({ error: "Internal server error" });
}
};
}


Loading
Loading