env + perms + tools
This commit is contained in:
parent
3c5b60e1aa
commit
6b815a6a68
@ -10,6 +10,7 @@ User=node
|
||||
Group=node
|
||||
|
||||
Environment="CONFIGFILE=/home/node/config/config.json"
|
||||
Environment="NODE_ENV=production"
|
||||
WorkingDirectory=/home/node/app
|
||||
ExecStart=/usr/bin/node /home/node/app/dist/api/src/app.js
|
||||
|
||||
|
122
api/package-lock.json
generated
122
api/package-lock.json
generated
@ -8,6 +8,7 @@
|
||||
"name": "api",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"connect-mongo": "^4.6.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.1",
|
||||
"express-session": "^1.17.3",
|
||||
@ -279,6 +280,17 @@
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"node_modules/asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@ -313,6 +325,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
||||
@ -451,6 +468,42 @@
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/connect-mongo": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-4.6.0.tgz",
|
||||
"integrity": "sha512-8new4Z7NLP3CGP65Aw6ls3xDBeKVvHRSh39CXuDZTQsvpeeU9oNMzfFgvqmHqZ6gWpxIl663RyoVEmCAGf1yOg==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"kruptein": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mongodb": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/connect-mongo/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/connect-mongo/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -921,6 +974,17 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kruptein": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.5.tgz",
|
||||
"integrity": "sha512-c1pyg/HKep8y5l+AoiicTs94k4bnzBSiS1b8NQcnQDtv9Yh45rNLuDIUwEwawmuFYpcA5xqhG7k0LqiMhrBPXw==",
|
||||
"dependencies": {
|
||||
"asn1.js": "^5.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">8"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@ -989,6 +1053,11 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -1950,6 +2019,17 @@
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"requires": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@ -1967,6 +2047,11 @@
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
||||
@ -2064,6 +2149,30 @@
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"connect-mongo": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-4.6.0.tgz",
|
||||
"integrity": "sha512-8new4Z7NLP3CGP65Aw6ls3xDBeKVvHRSh39CXuDZTQsvpeeU9oNMzfFgvqmHqZ6gWpxIl663RyoVEmCAGf1yOg==",
|
||||
"requires": {
|
||||
"debug": "^4.3.1",
|
||||
"kruptein": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -2415,6 +2524,14 @@
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"kruptein": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.5.tgz",
|
||||
"integrity": "sha512-c1pyg/HKep8y5l+AoiicTs94k4bnzBSiS1b8NQcnQDtv9Yh45rNLuDIUwEwawmuFYpcA5xqhG7k0LqiMhrBPXw==",
|
||||
"requires": {
|
||||
"asn1.js": "^5.4.1"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@ -2465,6 +2582,11 @@
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "CONFIGFILE=config/config.json ts-node-dev --respawn --transpile-only ./src/app.ts",
|
||||
"dev": "CONFIGFILE=config/config.json NODE_ENV=dev ts-node-dev --respawn --transpile-only ./src/app.ts",
|
||||
"start": "npm run build && CONFIGFILE=config/config.json node ./dist/api/src/app.js",
|
||||
"prettier": "prettier -w ./src"
|
||||
},
|
||||
@ -23,6 +23,7 @@
|
||||
"typescript": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"connect-mongo": "^4.6.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.1",
|
||||
"express-session": "^1.17.3",
|
||||
|
@ -25,7 +25,7 @@ const services: Services = {
|
||||
userModel: new UserModel(db),
|
||||
};
|
||||
|
||||
const server = new Server(config.server, services);
|
||||
const server = new Server(config.server, config.mongo, services);
|
||||
|
||||
server.start(() =>
|
||||
console.log(
|
||||
|
@ -2,7 +2,6 @@ import { ErrorRequestHandler, Request, RequestHandler } from 'express';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { validationResult } from 'express-validator';
|
||||
import { UserInfo, UserRoles } from '@core';
|
||||
import permissions from './permissions';
|
||||
|
||||
declare module 'express-session' {
|
||||
interface SessionData {
|
||||
@ -21,62 +20,42 @@ export function RequestId(): RequestHandler {
|
||||
};
|
||||
}
|
||||
|
||||
export function checkPermissions(): RequestHandler {
|
||||
const getRoute = (url: string): string => {
|
||||
for (const route in permissions) {
|
||||
if (url.startsWith(route)) return route;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const canAccess = (req: Request): boolean => {
|
||||
const user = req.session.user;
|
||||
if (!user) return false;
|
||||
|
||||
//Logout
|
||||
if (req.url === '/user/logout') {
|
||||
return true;
|
||||
}
|
||||
|
||||
//User Imself
|
||||
if (req.params.uuid === user.uuid) {
|
||||
return true;
|
||||
}
|
||||
export function CheckPermissions(): RequestHandler {
|
||||
function getResourceId(req: Request): string | null {
|
||||
console.log(req.url);
|
||||
if (req.params.uuid) return req.params.uuid;
|
||||
if (req.body.uuid) return req.body.uuid;
|
||||
return null;
|
||||
}
|
||||
|
||||
function canAccessRessource(user: UserInfo, uuid: string): boolean {
|
||||
if (user.uuid === uuid) return true;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
return (req, res, next) => {
|
||||
const route = getRoute(req.url);
|
||||
console.log(canAccess(req));
|
||||
console.log(route);
|
||||
|
||||
if (!req.session.user && req.url === '/user/login') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.session.user) {
|
||||
next({ status: 401, messsage: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!(route in permissions) ||
|
||||
(req.session.user.role !== permissions[route] &&
|
||||
req.session.user.role !== UserRoles.ADMIN) ||
|
||||
(!canAccess(req) && req.session.user.role !== UserRoles.ADMIN)
|
||||
) {
|
||||
next({ status: 401, messsage: 'Unauthorized' });
|
||||
if (req.session.user.role === UserRoles.ADMIN) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
req.session.user.role === UserRoles.ADMIN ||
|
||||
(req.session.user.role === permissions[route] && canAccess(req))
|
||||
) {
|
||||
const ressourceId = getResourceId(req);
|
||||
console.log(ressourceId);
|
||||
if (!ressourceId) {
|
||||
next({ status: 403, messsage: 'Forbidden' });
|
||||
return;
|
||||
}
|
||||
if (canAccessRessource(req.session.user, ressourceId)) {
|
||||
next();
|
||||
return;
|
||||
} else {
|
||||
next({ status: 403, messsage: 'Forbidden' });
|
||||
return;
|
||||
}
|
||||
|
||||
next({ status: 401, messsage: 'Unauthorized' });
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { UserRoles } from '@core';
|
||||
|
||||
const permissions = {
|
||||
'/user/login': UserRoles.USER,
|
||||
'/user/logout': UserRoles.USER,
|
||||
'/user/read': UserRoles.USER,
|
||||
'/user/create': UserRoles.ADMIN,
|
||||
};
|
||||
|
||||
export default permissions;
|
@ -2,10 +2,10 @@ import { Router } from 'express';
|
||||
import { Services } from '../../app';
|
||||
import * as user from './user';
|
||||
|
||||
export function getRoutes(services: Services) {
|
||||
export function Routes(services: Services) {
|
||||
const router = Router();
|
||||
|
||||
router.use('/user', user.getRoutes(services));
|
||||
router.use('/user', user.Routes(services));
|
||||
|
||||
return router;
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
import express, { Express } from 'express';
|
||||
import cors from 'cors';
|
||||
import session from 'express-session';
|
||||
import { getRoutes } from './router';
|
||||
import { RequestId, ErrorHandler, checkPermissions } from './middleware';
|
||||
import { Routes } from './router';
|
||||
import { RequestId, ErrorHandler } from './middleware';
|
||||
import { Services } from '../../app';
|
||||
import { ServerConfig } from '../../config';
|
||||
import { MongoConfig, ServerConfig } from '../../config';
|
||||
import { randomUUID } from 'crypto';
|
||||
import MongoStore from 'connect-mongo';
|
||||
|
||||
class Server {
|
||||
private app: Express;
|
||||
private config: ServerConfig;
|
||||
|
||||
constructor(config: ServerConfig, services: Services) {
|
||||
constructor(
|
||||
config: ServerConfig,
|
||||
mongoConfig: MongoConfig,
|
||||
services: Services,
|
||||
) {
|
||||
this.config = config;
|
||||
|
||||
this.app = express();
|
||||
@ -26,14 +31,23 @@ class Server {
|
||||
this.app.use(RequestId());
|
||||
this.app.use(
|
||||
session({
|
||||
proxy: process.env.NODE_ENV === 'production',
|
||||
secret: randomUUID(),
|
||||
cookie: { maxAge: 1000 * 3600 * 24 },
|
||||
cookie: {
|
||||
maxAge: 1000 * 3600 * 24,
|
||||
sameSite: 'strict',
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
store: MongoStore.create({
|
||||
mongoUrl: mongoConfig.uri,
|
||||
dbName: mongoConfig.dbName,
|
||||
touchAfter: 3600,
|
||||
}),
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
}),
|
||||
);
|
||||
//this.app.use(checkPermissions());
|
||||
this.app.use(getRoutes(services));
|
||||
this.app.use(Routes(services));
|
||||
this.app.use(ErrorHandler());
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
ReadUserSchema,
|
||||
LogoutUserSchema,
|
||||
} from './schema/user';
|
||||
import { getId, SchemaValidator } from './middleware';
|
||||
import { CheckPermissions, getId, SchemaValidator } from './middleware';
|
||||
|
||||
function LoginHandler(services: Services): RequestHandler {
|
||||
const login = LoginUser(services);
|
||||
@ -52,16 +52,9 @@ function ReadHandler(services: Services): RequestHandler {
|
||||
};
|
||||
}
|
||||
|
||||
export function getRoutes(services: Services) {
|
||||
export function Routes(services: Services) {
|
||||
const router = Router();
|
||||
|
||||
router.get(
|
||||
'/read/:uuid',
|
||||
ReadUserSchema(),
|
||||
SchemaValidator(),
|
||||
ReadHandler(services),
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/login',
|
||||
LoginUserSchema(),
|
||||
@ -74,10 +67,19 @@ export function getRoutes(services: Services) {
|
||||
SchemaValidator(),
|
||||
LogoutHandler(services),
|
||||
);
|
||||
router.get(
|
||||
'/read/:uuid',
|
||||
ReadUserSchema(),
|
||||
SchemaValidator(),
|
||||
CheckPermissions(),
|
||||
ReadHandler(services),
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/create',
|
||||
CreateUserSchema(),
|
||||
SchemaValidator(),
|
||||
CheckPermissions(),
|
||||
CreateHandler(services),
|
||||
);
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import json
|
||||
|
||||
apps: 'list[str]' = json.load(open('apps.json'))['apps']
|
||||
|
||||
print(len(apps), 'apps:', apps)
|
||||
|
||||
for app in apps:
|
||||
os.chdir(app)
|
||||
os.system('npm run build')
|
||||
os.chdir('..')
|
@ -2,8 +2,8 @@
|
||||
|
||||
useradd node -md /home/node -s /usr/sbin/nologin
|
||||
|
||||
python3 scripts/install.py
|
||||
python3 scripts/build.py
|
||||
python3 scripts/tools.py install
|
||||
python3 scripts/tools.py build
|
||||
|
||||
rm -r /var/www/html/*
|
||||
mv www/public/* /var/www/html
|
||||
|
@ -1,12 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import json
|
||||
|
||||
apps: 'list[str]' = json.load(open('apps.json'))['apps']
|
||||
|
||||
print(len(apps), 'apps:', apps)
|
||||
|
||||
for app in apps:
|
||||
os.chdir(app)
|
||||
os.system('npm ci')
|
||||
os.chdir('..')
|
@ -1,12 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import json
|
||||
|
||||
apps: 'list[str]' = json.load(open('apps.json'))['apps']
|
||||
|
||||
print(len(apps), 'apps:', apps)
|
||||
|
||||
for app in apps:
|
||||
os.chdir(app)
|
||||
os.system('npm run prettier')
|
||||
os.chdir('..')
|
32
scripts/tools.py
Executable file
32
scripts/tools.py
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
apps = ['core', 'api', 'www']
|
||||
commands = {
|
||||
'build': 'npm run build',
|
||||
'install': 'npm ci',
|
||||
'prettier': 'npm run prettier'
|
||||
}
|
||||
|
||||
|
||||
def print_commands():
|
||||
print('Commandes disponibles: ', [c for c in commands])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print_commands()
|
||||
exit()
|
||||
|
||||
cmd = sys.argv[1]
|
||||
if cmd not in commands:
|
||||
print('Commande \'%s\' non disponible' % cmd)
|
||||
print_commands()
|
||||
exit()
|
||||
|
||||
for app in apps:
|
||||
os.chdir(app)
|
||||
os.system(commands[cmd])
|
||||
os.chdir('..')
|
Loading…
x
Reference in New Issue
Block a user