Skip to content

Commit 1077848

Browse files
authored
[OGUI-1715] Implement initial structure and functionality of the Central System. (#3020)
* sets up the initial structure for the Central System / Token Exchange Service. * includes basic functionality, placeholder logic, src/ and dist/ separation, TypeScript config, module-controller-service structure, tests and required Node modules.
1 parent 86a3431 commit 1077848

23 files changed

Lines changed: 8115 additions & 1710 deletions

.github/workflows/tokenization.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
uses: actions/setup-node@v5
2020
with:
2121
node-version: '22.x'
22-
- run: (cd Tokenization/backend; npm i)
22+
- run: (cd Tokenization/backend/central-system; npm i)
2323
lint-check-webapp:
2424
name: Check eslint rules for webapp on ubuntu-latest
2525
runs-on: ubuntu-latest
@@ -46,3 +46,16 @@ jobs:
4646
with:
4747
node-version: '22.x'
4848
- run: (cd Tokenization/webapp; npm run docker:test)
49+
50+
central-system-test:
51+
needs: lint-check-backend
52+
name: Central System backend tests
53+
runs-on: ubuntu-latest
54+
timeout-minutes: 6
55+
steps:
56+
- uses: actions/checkout@v5
57+
- name: Setup node
58+
uses: actions/setup-node@v5
59+
with:
60+
node-version: '22.x'
61+
- run: (cd Tokenization/backend/central-system; npm i; npm run test)

Tokenization/.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
webapp/node_modules
33
webapp/.react-router
44
webapp/build
5-
backend/node_modules
65
backend/wrapper/dist/
76
backend/wrapper/node_modules/
8-
backend/wrapper/src/run_tests/
7+
backend/wrapper/src/run_tests/
8+
backend/node_modules
9+
backend/certs
10+
backend/central-system/dist
11+
backend/central-system/node_modules
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { HttpServer } from '@aliceo2/web-ui';
16+
17+
import CentralSystem from './dist/modules/CentralSystem.js';
18+
19+
const http = new HttpServer({ port: 8080, allow: '*' });
20+
21+
http.get(
22+
'/healthcheck',
23+
(req, res) => {
24+
res.status(200).send();
25+
},
26+
{ public: true }
27+
);
28+
29+
const centralSystemModel = new CentralSystem(4041);
30+
http.get(
31+
'/tokens/get',
32+
centralSystemModel.tokenController.getTokensHandler.bind(
33+
centralSystemModel.tokenController
34+
),
35+
{
36+
public: true,
37+
}
38+
);
39+
40+
http.post(
41+
'/tokens/create',
42+
centralSystemModel.tokenController.createTokenHandler.bind(
43+
centralSystemModel.tokenController
44+
),
45+
{ public: true }
46+
);
47+
48+
http.post(
49+
'/tokens/revoke',
50+
centralSystemModel.tokenController.revokeTokenHandler.bind(
51+
centralSystemModel.tokenController
52+
),
53+
{ public: true }
54+
);
55+
56+
// frontend test endpoints below
57+
const fakeTokens = new Map([
58+
[
59+
1,
60+
{
61+
tokenId: 1,
62+
last4chars: 'abcd',
63+
serviceFrom: 'Service 1',
64+
serviceTo: 'Service 2',
65+
exp: '2026-01-12T11:31:12',
66+
issuer: 'central-system',
67+
iat: '2025-10-01T10:00:00',
68+
permissions: ['GET', 'POST'],
69+
},
70+
],
71+
[
72+
2,
73+
{
74+
tokenId: 2,
75+
last4chars: 'wxyz',
76+
serviceFrom: 'Service 3',
77+
serviceTo: 'Service 4',
78+
exp: '2025-11-15T08:45:30',
79+
issuer: 'admin-portal',
80+
iat: '2025-09-15T14:22:10',
81+
permissions: ['GET'],
82+
},
83+
],
84+
[
85+
3,
86+
{
87+
tokenId: 3,
88+
last4chars: 'efgh',
89+
serviceFrom: 'Service 2',
90+
serviceTo: 'Service 1',
91+
exp: '2026-03-20T16:30:00',
92+
issuer: 'central-system',
93+
iat: '2025-10-02T09:15:00',
94+
permissions: ['GET', 'POST', 'PUT', 'DELETE'],
95+
},
96+
],
97+
[
98+
4,
99+
{
100+
tokenId: 4,
101+
last4chars: '1234',
102+
serviceFrom: 'Service 1',
103+
serviceTo: 'Service 3',
104+
exp: '2026-02-05T12:00:00',
105+
issuer: 'api-gateway',
106+
iat: '2025-09-25T11:30:45',
107+
permissions: ['GET', 'PUT'],
108+
},
109+
],
110+
]);
111+
112+
const fakeLogs = new Map([
113+
[1, []],
114+
[
115+
2,
116+
[
117+
{ id: 1, title: 'The first token ever', content: 'Log for token' },
118+
{
119+
id: 3,
120+
title: 'No second log?',
121+
content: 'Looks like second log is lost somewhere',
122+
},
123+
],
124+
],
125+
]);
126+
127+
http.get(
128+
'/tokens',
129+
(req, res) => {
130+
// Fake long page load
131+
setTimeout(() => res.status(200).json([...fakeTokens.values()]), 1000);
132+
},
133+
{ public: true }
134+
);
135+
136+
http.get(
137+
'/tokens/:tokenId',
138+
(req, res) => {
139+
const tokenId = parseInt(req.params.tokenId, 10);
140+
const token = fakeTokens.get(tokenId) ?? null;
141+
142+
if (!token) {
143+
res.status(404).json({ error: `No token found with id ${tokenId}` });
144+
return;
145+
}
146+
147+
res.status(200).json(token);
148+
},
149+
{ public: true }
150+
);
151+
152+
http.get(
153+
'/tokens/:tokenId/logs',
154+
(req, res) => {
155+
const tokenId = parseInt(req.params.tokenId, 10);
156+
157+
// Artificially add an error
158+
if (tokenId === 3) {
159+
res
160+
.status(500)
161+
.json({
162+
error: `An error occurred when trying to load logs for token ${tokenId}`,
163+
});
164+
return;
165+
}
166+
167+
const logs = fakeLogs.get(tokenId) ?? [];
168+
169+
if (!logs) {
170+
res
171+
.status(404)
172+
.json({ error: `No logs found found for token ${tokenId}` });
173+
return;
174+
}
175+
176+
setTimeout(() => res.status(200).json(logs), 1000);
177+
},
178+
{ public: true }
179+
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
testEnvironment: "node",
4+
roots: ["<rootDir>"],
5+
moduleFileExtensions: ["ts", "js", "json"],
6+
extensionsToTreatAsEsm: [".ts"],
7+
8+
moduleNameMapper: {
9+
"^(\\.{1,2}/.*)\\.js$": "$1",
10+
},
11+
12+
transform: {
13+
"^.+\\.tsx?$": [
14+
"ts-jest",
15+
{
16+
useESM: true,
17+
tsconfig: "<rootDir>/tsconfig.json",
18+
},
19+
],
20+
},
21+
};

0 commit comments

Comments
 (0)