Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • tuanh/backend-core
1 result
Show changes
Commits on Source (222)
node_modules node_modules
.git .git
.gitignore .gitignore
data
kong.yml
coverage
.env*
node_modules node_modules
bin bin
data
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
}, },
"rules": { "rules": {
// "no-console": "off", // "no-console": "off",
"func-names": "off", "func-names": "warn",
"no-underscore-dangle": "off", "no-underscore-dangle": "warn",
"consistent-return": "off", "consistent-return": "warn",
"jest/expect-expect": "off", "jest/expect-expect": "warn",
"security/detect-object-injection": "off", "security/detect-object-injection": "warn",
"camelcase": "off", "camelcase": "warn",
"import/no-unresolved": [ "import/no-unresolved": [
"error", "error",
{ {
...@@ -36,4 +36,4 @@ ...@@ -36,4 +36,4 @@
} }
] ]
} }
} }
\ No newline at end of file
...@@ -13,3 +13,8 @@ coverage ...@@ -13,3 +13,8 @@ coverage
# Local Netlify folder # Local Netlify folder
.netlify .netlify
kong.yml
data
node_modules node_modules
coverage coverage
data
...@@ -4,12 +4,13 @@ RUN mkdir -p /usr/src/playground-be && chown -R node:node /usr/src/playground-be ...@@ -4,12 +4,13 @@ RUN mkdir -p /usr/src/playground-be && chown -R node:node /usr/src/playground-be
WORKDIR /usr/src/playground-be WORKDIR /usr/src/playground-be
COPY package.json yarn.lock ./ COPY package.json ./
USER node USER node
RUN yarn install --pure-lockfile
COPY --chown=node:node . . COPY --chown=node:node . .
RUN yarn install
EXPOSE 8080 EXPOSE 8080
# RESTful API Node Server Boilerplate # RESTful API Node Server Boilerplate - te
[![Build Status](https://travis-ci.org/hagopj13/node-express-boilerplate.svg?branch=master)](https://travis-ci.org/hagopj13/node-express-boilerplate) [![Build Status](https://travis-ci.org/hagopj13/node-express-boilerplate.svg?branch=master)](https://travis-ci.org/hagopj13/node-express-boilerplate)
[![Coverage Status](https://coveralls.io/repos/github/hagopj13/node-express-boilerplate/badge.svg?branch=master)](https://coveralls.io/github/hagopj13/node-express-boilerplate?branch=master) [![Coverage Status](https://coveralls.io/repos/github/hagopj13/node-express-boilerplate/badge.svg?branch=master)](https://coveralls.io/github/hagopj13/node-express-boilerplate?branch=master)
......
version: '3'
services: services:
playground-be: playground-be:
command: yarn dev -L command: yarn dev -L
volumes:
- .:/usr/src/playground-be
restart: no
upload: upload:
command: npm start command: npm start
restart: no
playground-db:
ports:
- "27017:27017"
restart: no
kong:
restart: no
version: '3'
services: services:
playground-be: playground-be:
command: yarn dev -L command: yarn start
upload: upload:
command: npm run prod command: npm run prod
version: '3'
services: services:
playground-be: playground-be:
container_name: playground-be-test
command: yarn test command: yarn test
volumes:
- .:/usr/src/playground-be
# upload/Dockerfile
version: '3'
services: services:
kong:
platform: linux/amd64
image: kong:3.7.1-ubuntu
container_name: ${ENV:-dev}-kong
environment:
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /kong/declarative/kong.yml
ports:
- "${KONG_PROXY_PORT}:8000"
restart: always
networks:
- node-network
volumes:
- "./:/kong/declarative/"
depends_on:
- playground-be
playground-be: playground-be:
platform: linux/amd64
container_name: ${ENV:-dev}-playground-be
build: . build: .
image: playground-be image: boschvn/playground-be:${IMAGE_TAG:-latest}
ports: env_file:
- '${PORT}:${PORT}' - .env
depends_on: depends_on:
- playground-db - playground-db
- upload - upload
volumes:
- .:/usr/src/playground-be
networks: networks:
- node-network - node-network
restart: always
command: yarn start
playground-db: playground-db:
container_name: ${DB_CONTAINER_NAME:-playground-db}
image: mongo:4.4.6-bionic image: mongo:4.4.6-bionic
ports:
- '${MONGO_EXPOSE_PORT}:27017'
volumes: volumes:
- dbdata:/data/db - dbdata:/data/db
networks: networks:
- node-network - node-network
restart: always
upload: upload:
build: ./upload/ platform: linux/amd64
image: upload container_name: ${ENV:-dev}-upload
ports: image: boschvn/upload:dcdc95a
- '${UPLOAD_PORT}:${UPLOAD_PORT}' env_file:
- .env
volumes: volumes:
- ./upload:/usr/src/upload
- /usr/src/upload/node_modules/
- '${UPLOAD_PATH}:/usr/src/upload/data' - '${UPLOAD_PATH}:/usr/src/upload/data'
networks: networks:
- node-network - node-network
restart: always
command: npm run prod
volumes: volumes:
dbdata: dbdata:
......
_format_version: '3.0'
_transform: true
services:
- host: ${ENV}-playground-be
name: main
port: ${PORT}
protocol: http
routes:
- name: main_route
methods:
- GET
- PUT
- POST
- PATCH
- DELETE
- OPTIONS
- HEAD
- CONNECT
- TRACE
read_timeout: 180000
plugins:
- name: rate-limiting
enabled: true
protocols:
- grpc
- grpcs
- http
- https
config:
fault_tolerant: true
hide_client_headers: false
minute: 120
limit_by: header
header_name: x-forwarded-for
policy: local
sync_rate: -1
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
}, },
"scripts": { "scripts": {
"start": "pm2 start ecosystem.config.json --no-daemon", "start": "pm2 start ecosystem.config.json --no-daemon",
"dev": "cross-env NODE_ENV=development nodemon src/index.js", "dev": "cross-env NODE_ENV=development nodemon --ignore 'data/*' src/index.js",
"test": "jest -i --colors --verbose --detectOpenHandles", "test": "jest -i --colors --verbose --detectOpenHandles",
"test:watch": "jest -i --watchAll", "test:watch": "jest -i --watchAll",
"coverage": "jest -i --coverage", "coverage": "jest -i --coverage",
...@@ -66,8 +66,10 @@ ...@@ -66,8 +66,10 @@
"helmet": "^4.1.0", "helmet": "^4.1.0",
"http-proxy-middleware": "^3.0.0", "http-proxy-middleware": "^3.0.0",
"http-status": "^1.7.4", "http-status": "^1.7.4",
"jimp": "^0.22.12",
"joi": "^17.3.0", "joi": "^17.3.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"moment": "^2.24.0", "moment": "^2.24.0",
"mongoose": "^5.7.7", "mongoose": "^5.7.7",
"morgan": "^1.9.1", "morgan": "^1.9.1",
...@@ -75,15 +77,17 @@ ...@@ -75,15 +77,17 @@
"passport": "^0.4.0", "passport": "^0.4.0",
"passport-jwt": "^4.0.0", "passport-jwt": "^4.0.0",
"pm2": "^5.1.0", "pm2": "^5.1.0",
"socket.io": "^4.7.5", "socket.io": "^4.8.0",
"swagger-jsdoc": "^6.0.8", "swagger-jsdoc": "^6.0.8",
"swagger-ui-express": "^4.1.6", "swagger-ui-express": "^4.1.6",
"utf-8-validate": "^6.0.4", "utf-8-validate": "^6.0.4",
"validator": "^13.0.0", "validator": "^13.0.0",
"winston": "^3.2.1", "websocket": "^1.0.35",
"xss-clean": "^0.1.1" "winston": "^3.2.1"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.17.12",
"@types/mongoose": "^5.11.97",
"coveralls": "^3.0.7", "coveralls": "^3.0.7",
"eslint": "^7.0.0", "eslint": "^7.0.0",
"eslint-config-airbnb-base": "^14.0.0", "eslint-config-airbnb-base": "^14.0.0",
......
const express = require('express'); const express = require('express');
const helmet = require('helmet'); const helmet = require('helmet');
const xss = require('xss-clean');
const cookies = require('cookie-parser'); const cookies = require('cookie-parser');
const mongoSanitize = require('express-mongo-sanitize'); const mongoSanitize = require('express-mongo-sanitize');
const compression = require('compression'); const compression = require('compression');
...@@ -16,7 +15,7 @@ const routesV2 = require('./routes/v2'); ...@@ -16,7 +15,7 @@ const routesV2 = require('./routes/v2');
const { errorConverter, errorHandler } = require('./middlewares/error'); const { errorConverter, errorHandler } = require('./middlewares/error');
const ApiError = require('./utils/ApiError'); const ApiError = require('./utils/ApiError');
const setupProxy = require('./config/proxyHandler'); const setupProxy = require('./config/proxyHandler');
const LLMServices = require('./services/llm.service'); const { init: initSocketIO } = require('./config/socket');
const app = express(); const app = express();
...@@ -38,7 +37,6 @@ app.use(express.json({ limit: '50mb', strict: false })); ...@@ -38,7 +37,6 @@ app.use(express.json({ limit: '50mb', strict: false }));
app.use(express.urlencoded({ extended: true, limit: '50mb', parameterLimit: 10000 })); app.use(express.urlencoded({ extended: true, limit: '50mb', parameterLimit: 10000 }));
// sanitize request data // sanitize request data
app.use(xss());
app.use(mongoSanitize()); app.use(mongoSanitize());
// gzip compression // gzip compression
...@@ -47,14 +45,7 @@ app.use(compression()); ...@@ -47,14 +45,7 @@ app.use(compression());
// enable cors // enable cors
app.use( app.use(
cors({ cors({
origin: [ origin: config.cors.regex,
/localhost:\d+/,
/\.digitalauto\.tech$/,
/\.digitalauto\.asia$/,
/\.digital\.auto$/,
'https://digitalauto.netlify.app',
/127\.0\.0\.1:\d+/,
],
credentials: true, credentials: true,
}) })
); );
...@@ -64,18 +55,14 @@ app.options('*', cors()); ...@@ -64,18 +55,14 @@ app.options('*', cors());
app.use(passport.initialize()); app.use(passport.initialize());
passport.use('jwt', jwtStrategy); passport.use('jwt', jwtStrategy);
// limit repeated failed requests to auth endpoints
// if (config.env === 'production') {
// app.use('/v1/auth', authLimiter);
// app.use('/v2/auth', authLimiter);
// }
// v1 api routes // v1 api routes
app.use('/v1', routes); app.use('/v1', routes);
app.use('/v2', routesV2); app.use('/v2', routesV2);
// Setup proxy to other services // Setup proxy to other services
setupProxy(app); setupProxy(app);
const server = require('http').createServer(app);
initSocketIO(server);
// send back a 404 error for any unknown api request // send back a 404 error for any unknown api request
app.use((req, res, next) => { app.use((req, res, next) => {
...@@ -88,4 +75,12 @@ app.use(errorConverter); ...@@ -88,4 +75,12 @@ app.use(errorConverter);
// handle error // handle error
app.use(errorHandler); app.use(errorHandler);
// Test function
// (async () => {
// try {
// } catch (error) {
// console.log(error);
// }
// })();
module.exports = app; module.exports = app;
...@@ -9,6 +9,9 @@ const envVarsSchema = Joi.object() ...@@ -9,6 +9,9 @@ const envVarsSchema = Joi.object()
NODE_ENV: Joi.string().valid('production', 'development', 'test').required(), NODE_ENV: Joi.string().valid('production', 'development', 'test').required(),
PORT: Joi.number().default(3000), PORT: Joi.number().default(3000),
MONGODB_URL: Joi.string().required().description('Mongo DB url'), MONGODB_URL: Joi.string().required().description('Mongo DB url'),
// CORS Settings
CORS_ORIGIN: Joi.string().description('CORS regex'),
// JWT
JWT_SECRET: Joi.string().required().description('JWT secret key'), JWT_SECRET: Joi.string().required().description('JWT secret key'),
JWT_ACCESS_EXPIRATION_MINUTES: Joi.number().default(30).description('minutes after which access tokens expire'), JWT_ACCESS_EXPIRATION_MINUTES: Joi.number().default(30).description('minutes after which access tokens expire'),
JWT_REFRESH_EXPIRATION_DAYS: Joi.number().default(30).description('days after which refresh tokens expire'), JWT_REFRESH_EXPIRATION_DAYS: Joi.number().default(30).description('days after which refresh tokens expire'),
...@@ -18,33 +21,46 @@ const envVarsSchema = Joi.object() ...@@ -18,33 +21,46 @@ const envVarsSchema = Joi.object()
JWT_VERIFY_EMAIL_EXPIRATION_MINUTES: Joi.number() JWT_VERIFY_EMAIL_EXPIRATION_MINUTES: Joi.number()
.default(10) .default(10)
.description('minutes after which verify email token expires'), .description('minutes after which verify email token expires'),
JWT_COOKIE_NAME: Joi.string().default('token').description('JWT cookie name'),
JWT_COOKIE_DOMAIN: Joi.string().default('').description('JWT cookie domain'),
SMTP_HOST: Joi.string().description('server that will send the emails'), SMTP_HOST: Joi.string().description('server that will send the emails'),
SMTP_PORT: Joi.number().description('port to connect to the email server'), SMTP_PORT: Joi.number().description('port to connect to the email server'),
SMTP_USERNAME: Joi.string().description('username for email server'), SMTP_USERNAME: Joi.string().description('username for email server'),
SMTP_PASSWORD: Joi.string().description('password for email server'), SMTP_PASSWORD: Joi.string().description('password for email server'),
EMAIL_FROM: Joi.string().description('the from field in the emails sent by the app'), EMAIL_FROM: Joi.string().description('the from field in the emails sent by the app'),
CACHE_BASE_URL: Joi.string().required().description('Cache base url'), CACHE_BASE_URL: Joi.string().description('Cache base url'),
LOG_BASE_URL: Joi.string().required().description('Log base url'), LOG_BASE_URL: Joi.string().description('Log base url'),
CLIENT_BASE_URL: Joi.string().description('Client base url').default('http://localhost:3000'), CLIENT_BASE_URL: Joi.string().description('Client base url').default('http://localhost:3000'),
BREVO_API_KEY: Joi.string().required().description('Brevo API key'), BREVO_API_KEY: Joi.string().description('Brevo API key'),
BREVO_BASE_URL: Joi.string().required().description('Brevo base url'), BREVO_BASE_URL: Joi.string().description('Brevo base url'),
GITHUB_CLIENT_ID: Joi.string().required().description('Github client id'), GITHUB_CLIENT_ID: Joi.string().description('Github client id'),
GITHUB_CLIENT_SECRET: Joi.string().required().description('Github client secret'), GITHUB_CLIENT_SECRET: Joi.string().description('Github client secret'),
UPLOAD_PORT: Joi.number().required().description('Upload port'), UPLOAD_PORT: Joi.number().required().description('Upload port'),
UPLOAD_DOMAIN: Joi.string().required().description('Upload domain'),
// AWS, // AWS,
AWS_PUBLIC_KEY: Joi.string().required().description('AWS public key'), AWS_PUBLIC_KEY: Joi.string().description('AWS public key'),
AWS_SECRET_KEY: Joi.string().required().description('AWS secret key'), AWS_SECRET_KEY: Joi.string().description('AWS secret key'),
// OpenAI, // OpenAI,
OPENAI_API_KEY: Joi.string().required().description('OpenAI API key'), OPENAI_API_KEY: Joi.string().description('OpenAI API key'),
OPENAI_ENDPOINT_URL: Joi.string().required().description('OpenAI endpoint url'), OPENAI_ENDPOINT_URL: Joi.string().description('OpenAI endpoint url'),
// GenAI // GenAI
GENAI_ALLOWED_EMAILS: Joi.string().required().description('GenAI allowed emails'), GENAI_ALLOWED_EMAILS: Joi.string().description('GenAI allowed emails'),
// ETAS // ETAS
ETAS_ENABLED: Joi.boolean().description('ETAS enabled'), ETAS_ENABLED: Joi.boolean().description('ETAS enabled'),
ETAS_CLIENT_ID: Joi.string().description('ETAS client id'), ETAS_CLIENT_ID: Joi.string().description('ETAS client id'),
ETAS_CLIENT_SECRET: Joi.string().description('ETAS client secret'), ETAS_CLIENT_SECRET: Joi.string().description('ETAS client secret'),
ETAS_SCOPE: Joi.string().description('ETAS scope'), ETAS_SCOPE: Joi.string().description('ETAS scope'),
ETAS_INSTANCE_ENDPOINT: Joi.string().description('ETAS instance endpoint'), ETAS_INSTANCE_ENDPOINT: Joi.string().description('ETAS instance endpoint'),
ETAS_DEV_INSTANCE_ENDPOINT: Joi.string().description('ETAS dev instance endpoint'),
// Certivity
CERTIVITY_CLIENT_ID: Joi.string().description('Certivity client id'),
CERTIVITY_CLIENT_SECRET: Joi.string().description('Certivity client secret'),
STRICT_AUTH: Joi.boolean().description('Strict auth'),
// Admin emails
ADMIN_EMAILS: Joi.string().description('Admin emails'),
ADMIN_PASSWORD: Joi.string().description('Admin password'),
// Change Logs max size
LOGS_MAX_SIZE: Joi.number().default(100).description('Max size of change logs in megabytes'),
}) })
.unknown(); .unknown();
...@@ -57,6 +73,14 @@ if (error) { ...@@ -57,6 +73,14 @@ if (error) {
const config = { const config = {
env: envVars.NODE_ENV, env: envVars.NODE_ENV,
port: envVars.PORT, port: envVars.PORT,
strictAuth: envVars.STRICT_AUTH,
cors: {
regex: (envVars.CORS_ORIGIN || 'localhost:\\d+,127\\.0\\.0\\.1:\\d+')
.split(',')
.map((i) => i.trim())
.filter(Boolean)
.map((i) => new RegExp(i)),
},
mongoose: { mongoose: {
url: envVars.MONGODB_URL + (envVars.NODE_ENV === 'test' ? '-test' : ''), url: envVars.MONGODB_URL + (envVars.NODE_ENV === 'test' ? '-test' : ''),
options: { options: {
...@@ -72,11 +96,14 @@ const config = { ...@@ -72,11 +96,14 @@ const config = {
refreshExpirationDays: envVars.JWT_REFRESH_EXPIRATION_DAYS, refreshExpirationDays: envVars.JWT_REFRESH_EXPIRATION_DAYS,
resetPasswordExpirationMinutes: envVars.JWT_RESET_PASSWORD_EXPIRATION_MINUTES, resetPasswordExpirationMinutes: envVars.JWT_RESET_PASSWORD_EXPIRATION_MINUTES,
verifyEmailExpirationMinutes: envVars.JWT_VERIFY_EMAIL_EXPIRATION_MINUTES, verifyEmailExpirationMinutes: envVars.JWT_VERIFY_EMAIL_EXPIRATION_MINUTES,
cookieRefreshOptions: { cookie: {
// TODO: change this to true when deploy name: envVars.JWT_COOKIE_NAME,
secure: true, options: {
httpOnly: true, secure: true,
sameSite: 'None', httpOnly: true,
sameSite: 'None',
...(envVars.NODE_ENV === 'production' && { domain: envVars.JWT_COOKIE_DOMAIN }),
},
}, },
}, },
email: { email: {
...@@ -111,6 +138,7 @@ const config = { ...@@ -111,6 +138,7 @@ const config = {
services: { services: {
upload: { upload: {
port: envVars.UPLOAD_PORT, port: envVars.UPLOAD_PORT,
domain: envVars.UPLOAD_DOMAIN,
}, },
log: { log: {
port: envVars.LOG_PORT || 9600, port: envVars.LOG_PORT || 9600,
...@@ -128,7 +156,7 @@ const config = { ...@@ -128,7 +156,7 @@ const config = {
secretKey: envVars.AWS_SECRET_KEY, secretKey: envVars.AWS_SECRET_KEY,
}, },
genAI: { genAI: {
allowedEmails: envVars.GENAI_ALLOWED_EMAILS.split(','), allowedEmails: envVars.GENAI_ALLOWED_EMAILS?.split(',') || [],
}, },
etas: { etas: {
enabled: envVars.ETAS_ENABLED, enabled: envVars.ETAS_ENABLED,
...@@ -136,7 +164,23 @@ const config = { ...@@ -136,7 +164,23 @@ const config = {
clientSecret: envVars.ETAS_CLIENT_SECRET, clientSecret: envVars.ETAS_CLIENT_SECRET,
scope: envVars.ETAS_SCOPE, scope: envVars.ETAS_SCOPE,
instanceEndpoint: envVars.ETAS_INSTANCE_ENDPOINT, instanceEndpoint: envVars.ETAS_INSTANCE_ENDPOINT,
developmentEndpoint: envVars.ETAS_DEV_INSTANCE_ENDPOINT,
},
githubIssueSubmitUrl: 'https://api.github.com/repos/digital-auto/vehicle_signal_specification/issues',
certivity: {
authBaseUrl: 'https://certivity-dev.eu.auth0.com/oauth/token',
authAudience: 'https://service-api-dev.certivity.io',
authGrantType: 'client_credentials',
clientId: envVars.CERTIVITY_CLIENT_ID,
clientSecret: envVars.CERTIVITY_CLIENT_SECRET,
regulationBaseUrl: 'https://ctvt-service-api.azurewebsites.net/api/v1/protected/regulation',
},
sso: {
msGraphMeEndpoint: 'https://graph.microsoft.com/v1.0/me',
}, },
adminEmails: envVars.ADMIN_EMAILS?.split(',') || [],
adminPassword: envVars.ADMIN_PASSWORD,
logsMaxSize: envVars.LOGS_MAX_SIZE,
}; };
if (config.env === 'development') { if (config.env === 'development') {
......
...@@ -4,47 +4,56 @@ const { getFirestore } = require('firebase-admin/firestore'); ...@@ -4,47 +4,56 @@ const { getFirestore } = require('firebase-admin/firestore');
const { getStorage } = require('firebase-admin/storage'); const { getStorage } = require('firebase-admin/storage');
require('dotenv').config(); require('dotenv').config();
const { privateKey } = JSON.parse(process.env.FIREBASE_PRIVATE_KEY); const { privateKey } = JSON.parse(process.env.FIREBASE_PRIVATE_KEY || '{}');
const app = initializeApp({ const exportsObject = {
credential: cert({ db: null,
projectId: process.env.FIREBASE_PROJECT_ID, auth: null,
privateKey, getStorageRef: null,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL, REFS: null,
}), };
});
const storage = getStorage(); if (privateKey) {
const app = initializeApp({
credential: cert({
projectId: process.env.FIREBASE_PROJECT_ID,
privateKey,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
}),
});
const getStorageRef = (filename) => { const storage = getStorage();
const bucket = storage.bucket(); // Gets the default bucket
return bucket.file(filename); // Creates a reference to the file in the bucket
};
const db = getFirestore(app); const getStorageRef = (filename) => {
const auth = getAuth(app); const bucket = storage.bucket(); // Gets the default bucket
return bucket.file(filename); // Creates a reference to the file in the bucket
const REFS = { };
tenant: db.collection('tenant'),
model: db.collection('model'),
tags: db.collection('tags'),
prototype: db.collection('project'),
plugin: db.collection('plugin'),
media: db.collection('media'),
user: db.collection('user'),
feedback: db.collection('feedback'),
discussion: db.collection('discussion'),
activity_log: db.collection('activity_log'),
issue: db.collection('issue'),
survey: db.collection('survey'),
feature: db.collection('feature'),
api: db.collection('api'),
addOns: db.collection('addOns'),
};
module.exports = { const db = getFirestore(app);
db, const auth = getAuth(app);
auth,
getStorageRef, const REFS = {
REFS, tenant: db.collection('tenant'),
}; model: db.collection('model'),
tags: db.collection('tags'),
prototype: db.collection('project'),
plugin: db.collection('plugin'),
media: db.collection('media'),
user: db.collection('user'),
feedback: db.collection('feedback'),
discussion: db.collection('discussion'),
activity_log: db.collection('activity_log'),
issue: db.collection('issue'),
survey: db.collection('survey'),
feature: db.collection('feature'),
api: db.collection('api'),
addOns: db.collection('addOns'),
};
exportsObject.db = db;
exportsObject.auth = auth;
exportsObject.getStorageRef = getStorageRef;
exportsObject.REFS = REFS;
}
module.exports = exportsObject;
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt'); const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
const config = require('./config'); const config = require('./config');
const { tokenTypes } = require('./tokens'); const { tokenTypes } = require('./tokens');
const { User } = require('../models'); const { User, Asset } = require('../models');
const jwtOptions = { const jwtOptions = {
secretOrKey: config.jwt.secret, secretOrKey: config.jwt.secret,
...@@ -14,10 +14,14 @@ const jwtVerify = async (payload, done) => { ...@@ -14,10 +14,14 @@ const jwtVerify = async (payload, done) => {
throw new Error('Invalid token type'); throw new Error('Invalid token type');
} }
const user = await User.findById(payload.sub); const user = await User.findById(payload.sub);
if (!user) { if (user) {
return done(null, false); return done(null, user);
} }
done(null, user); const asset = await Asset.findById(payload.sub);
if (asset) {
return done(null, asset);
}
return done(null, false);
} catch (error) { } catch (error) {
done(error, false); done(error, false);
} }
...@@ -27,4 +31,5 @@ const jwtStrategy = new JwtStrategy(jwtOptions, jwtVerify); ...@@ -27,4 +31,5 @@ const jwtStrategy = new JwtStrategy(jwtOptions, jwtVerify);
module.exports = { module.exports = {
jwtStrategy, jwtStrategy,
jwtVerify,
}; };
...@@ -9,7 +9,7 @@ const roleRights = new Map(Object.entries(allRoles)); ...@@ -9,7 +9,7 @@ const roleRights = new Map(Object.entries(allRoles));
const PERMISSIONS = { const PERMISSIONS = {
// * // *
UNLIMITED_MODEL: 'unlimitedModel', UNLIMITED_MODEL: 'unlimitedModel',
MANAGE_USERS: 'manageUsers', ADMIN: 'manageUsers',
// model_id // model_id
READ_MODEL: 'readModel', READ_MODEL: 'readModel',
...@@ -17,14 +17,22 @@ const PERMISSIONS = { ...@@ -17,14 +17,22 @@ const PERMISSIONS = {
// genai, // genai,
GENERATIVE_AI: 'generativeAI', GENERATIVE_AI: 'generativeAI',
// read assets,
READ_ASSET: 'readAsset',
WRITE_ASSET: 'writeAsset',
// deploy hardware
DEPLOY_HARDWARE: 'deployHardware',
}; };
const PERMISSIONS_DESCRIPTION = { const PERMISSIONS_DESCRIPTION = {
[PERMISSIONS.UNLIMITED_MODEL]: 'Unlimited access', [PERMISSIONS.UNLIMITED_MODEL]: 'Unlimited access',
[PERMISSIONS.MANAGE_USERS]: 'Manage users', [PERMISSIONS.ADMIN]: 'Manage users',
[PERMISSIONS.READ_MODEL]: 'Read model', [PERMISSIONS.READ_MODEL]: 'Read model',
[PERMISSIONS.WRITE_MODEL]: 'Write model', [PERMISSIONS.WRITE_MODEL]: 'Write model',
[PERMISSIONS.GENERATIVE_AI]: 'Generative AI', [PERMISSIONS.GENERATIVE_AI]: 'Generative AI',
[PERMISSIONS.DEPLOY_HARDWARE]: 'Deploy hardware',
}; };
// The role here is applied for the resources that the user is not the owner of // The role here is applied for the resources that the user is not the owner of
...@@ -55,13 +63,37 @@ const ROLES = { ...@@ -55,13 +63,37 @@ const ROLES = {
permissions: [ permissions: [
PERMISSIONS.READ_MODEL, PERMISSIONS.READ_MODEL,
PERMISSIONS.WRITE_MODEL, PERMISSIONS.WRITE_MODEL,
PERMISSIONS.MANAGE_USERS, PERMISSIONS.ADMIN,
PERMISSIONS.UNLIMITED_MODEL, PERMISSIONS.UNLIMITED_MODEL,
PERMISSIONS.GENERATIVE_AI, PERMISSIONS.GENERATIVE_AI,
PERMISSIONS.READ_ASSET,
PERMISSIONS.WRITE_ASSET,
PERMISSIONS.DEPLOY_HARDWARE,
], ],
ref: 'admin', ref: 'admin',
name: 'Admin', name: 'Admin',
}, },
read_asset: {
permissions: [PERMISSIONS.READ_ASSET],
ref: 'read_asset',
name: 'Read asset',
},
write_asset: {
permissions: [PERMISSIONS.READ_ASSET, PERMISSIONS.WRITE_ASSET],
ref: 'write_asset',
name: 'Write asset',
},
deploy_hardware: {
permissions: [PERMISSIONS.DEPLOY_HARDWARE],
ref: 'deploy_hardware',
name: 'Deploy hardware',
},
};
const RESOURCES = {
MODEL: 'model',
PROTOTYPE: 'prototype',
ASSET: 'asset',
}; };
module.exports = { module.exports = {
...@@ -70,4 +102,5 @@ module.exports = { ...@@ -70,4 +102,5 @@ module.exports = {
ROLES, ROLES,
PERMISSIONS, PERMISSIONS,
PERMISSIONS_DESCRIPTION, PERMISSIONS_DESCRIPTION,
RESOURCES,
}; };
const { Server } = require('socket.io'); const { Server } = require('socket.io');
const logger = require('./logger'); const logger = require('./logger');
const ApiError = require('../utils/ApiError');
const httpStatus = require('http-status');
const jwt = require('jsonwebtoken');
const config = require('./config');
const { jwtVerify } = require('./passport');
const { tokenTypes } = require('./tokens');
const permissionService = require('../services/permission.service');
const { PERMISSIONS } = require('./roles');
let io = null; let io = null;
const init = (server) => { const init = (server) => {
io = new Server(server, { io = new Server(server, {
cors: { cors: {
origin: [ origin: config.cors.regex,
/localhost:\d+/,
/\.digitalauto\.tech$/,
/\.digitalauto\.asia$/,
/\.digital\.auto$/,
'https://digitalauto.netlify.app',
],
credentials: true, credentials: true,
}, },
}); });
io.use(function (socket, next) {
if (socket.handshake.query && socket.handshake.query.access_token) {
jwt.verify(socket.handshake.query.access_token, config.jwt.secret, async function (err, decoded) {
if (err) return next(new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate'));
await jwtVerify(
{
type: tokenTypes.ACCESS,
sub: decoded.sub,
},
async (error, user) => {
if (error || !user) {
return next(new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate'));
}
// if (!(await permissionService.hasPermission(user.id, PERMISSIONS.GENERATIVE_AI)))
// return next(new ApiError(httpStatus.UNAUTHORIZED, 'You are not authorized to access this'));
// }
socket.user = user;
next();
}
);
});
} else {
next(new ApiError(httpStatus.UNAUTHORIZED, 'Please authenticate'));
}
});
io.on('connection', () => { io.on('connection', () => {
logger.info('a user connected'); logger.info('a user connected');
}); });
......
...@@ -31,10 +31,22 @@ const deleteApi = catchAsync(async (req, res) => { ...@@ -31,10 +31,22 @@ const deleteApi = catchAsync(async (req, res) => {
res.status(httpStatus.NO_CONTENT).send(); res.status(httpStatus.NO_CONTENT).send();
}); });
const listVSSVersions = catchAsync(async (req, res) => {
const versions = await apiService.listVSSVersions();
res.send(versions);
});
const getVSSVersion = catchAsync(async (req, res) => {
const version = await apiService.getVSSVersion(req.params.name);
res.send(version);
});
module.exports = { module.exports = {
createApi, createApi,
getApiByModelId, getApiByModelId,
getApi, getApi,
updateApi, updateApi,
deleteApi, deleteApi,
listVSSVersions,
getVSSVersion,
}; };