added server management

pull/1/head
Valentin PUCCETTI 2023-09-11 15:21:36 +02:00
parent 298ef6d873
commit a034396dbe
23 changed files with 553 additions and 177 deletions

View File

@ -5,6 +5,8 @@ const session = require('express-session');
const databaseService = require('./services/database.service');
const bodyParser = require('body-parser');
userService = require("./services/users.service");
const groupService = require("./services/group.service");
const User = require('./model/user.model')
@ -50,10 +52,22 @@ app.use(function(req, res, next) {
});
app.get("/", (req, res) => {
if (req.session.loggedin === true) {
res.render('index', { user: req.session.user })
} else {
res.redirect("/login")
try {
if (req.session.loggedin === true) {
var stats = {}
Key.count({ where: { idOwner: req.session.user.id } }).then((result) => {
stats["keys"] = result
Member.count({ where: { userId: req.session.user.id } }).then((result) => {
stats["groups"] = result
res.render('index', { user: req.session.user, stats: stats })
})
})
} else {
res.redirect("/login")
}
} catch (e) {
console.log(e)
}
});
@ -62,9 +76,10 @@ app.get("/login", (req, res) => {
res.render('login')
});
try {
userService.makeAdmin(43043885)
} catch (e) {
}
app.use('/admin/', require('./routes/admin.route'));
app.use('/auth/', require('./routes/auth.route'));

View File

@ -4,11 +4,6 @@ const sequelize = require('../services/database.service');
class Key extends Model {}
Key.init({
idKey: {
type: DataTypes.STRING,
primaryKey: true,
required: true,
},
idOwner: {
type: DataTypes.INTEGER,
required: true,

27
model/server.model.js Normal file
View File

@ -0,0 +1,27 @@
const { Model, DataTypes} = require('sequelize');
const sequelize = require('../services/database.service');
class Server extends Model {}
Server.init({
hostname: {
type: DataTypes.STRING,
required: true,
},
ip: {
type: DataTypes.STRING,
required: true,
},
username: {
type: DataTypes.STRING,
required: true,
},
lastPull: {
type: DataTypes.DATE
}
}, {
sequelize,
modelName: 'server'
})
module.exports = Server;

View File

@ -1,9 +1,5 @@
const express = require('express');
const User = require("../model/user.model");
const Group = require("../model/group.model");
groupService = require("../services/group.service");
const Member = require("../model/member.model");
memberService = require("../services/members.service");
const User = require("../model/user.model")
var router = express.Router();
router.use('*', (req, res, next) => {
@ -20,74 +16,9 @@ router.use('*', (req, res, next) => {
}
});
router.get("/users",async (req, res) => {
User.findAll().then((users) => {
res.render('admin/users', { "users": users})
})
})
router.get("/groups", (req, res) => {
groupService.getGroupsWithMembers().then((groups) => {
res.render('admin/groups', { "groups": groups })
})
})
router.post("/groups/add", (req, res) => {
if (req.body.group_name) {
groupService.addGroup(req.body.group_name).then((result) => {
res.redirect("/admin/groups")
})
} else {
res.redirect("/admin/groups")
}
})
router.get("/groups/delete/:group", (req, res) => {
groupService.delGroup(req.params.group).then((result) => {
res.redirect("/admin/groups")
})
});
router.get("/groups/:name", async (req, res) => {
if (req.params.name === "new") {
res.render('admin/group_new')
} else {
Group.findOne({ where: { name: req.params.name } }).then((group) => {
groupService.groupUserList(req.params.name).then((result) => {
User.findAll().then((users) => {
for (user in users) {
if (JSON.stringify(result).includes(users[user].dataValues.id)) {
delete users[user]
}
}
res.render('admin/group_edit', { "group": group, "inGroup": result, "outGroup": users })
});
})
});
}
})
router.get('/members/:name/add/:user', (req, res) => {
memberService.addMember(req.params.user, req.params.name).then((result) => {
res.redirect('/admin/groups/' + req.params.name)
});
})
router.get('/members/:name/delete/:user', (req, res) => {
memberService.delMember(req.params.user, req.params.name).then((result) => {
res.redirect('/admin/groups/' + req.params.name)
});
})
router.use('/users/', require('../routes/admin/users.route'));
router.use('/members/', require('../routes/admin/members.route'));
router.use('/groups/', require('../routes/admin/groups.route'));
router.use('/servers/', require('../routes/admin/servers.route'));
module.exports = router;

View File

@ -0,0 +1,68 @@
const express = require('express');
const User = require("../../model/user.model");
const Group = require("../../model/group.model");
groupService = require("../../services/group.service");
memberService = require("../../services/members.service");
var router = express.Router();
router.get("/", (req, res) => {
try {
groupService.getGroupsWithMembers().then((groups) => {
res.render('admin/groups', { "groups": groups })
})
} catch (e) {
console.log(e)
}
})
router.post("/add", (req, res) => {
if (req.body.group_name) {
groupService.addGroup(req.body.group_name).then((result) => {
res.redirect("/admin/groups")
})
} else {
res.redirect("/admin/groups")
}
})
router.get("/delete/:group", (req, res) => {
try {
groupService.delGroup(req.params.group).then((result) => {
res.redirect("/admin/groups")
})
} catch (e) {
console.log(e)
}
});
router.get("/:name", async (req, res) => {
try {
if (req.params.name === "new") {
res.render('admin/group_new')
} else {
Group.findOne({ where: { name: req.params.name } }).then((group) => {
groupService.groupUserList(req.params.name).then((result) => {
User.findAll().then((users) => {
for (user in users) {
if (JSON.stringify(result).includes(users[user].dataValues.id)) {
delete users[user]
}
}
res.render('admin/group_edit', { "group": group, "inGroup": result, "outGroup": users })
});
})
});
}
} catch(e){
console.log(e)
}
})
module.exports = router;

View File

@ -0,0 +1,31 @@
const express = require('express');
const User = require("../../model/user.model");
const Group = require("../../model/group.model");
groupService = require("../../services/group.service");
const Member = require("../../model/member.model");
memberService = require("../../services/members.service");
var router = express.Router();
router.get('/:name/add/:user', (req, res) => {
try {
memberService.addMember(req.params.user, req.params.name).then((result) => {
res.redirect('/admin/groups/' + req.params.name)
});
} catch(e) {
console.log(e)
}
})
router.get('/:name/delete/:user', (req, res) => {
try {
memberService.delMember(req.params.user, req.params.name).then((result) => {
res.redirect('/admin/groups/' + req.params.name)
});
} catch(e) {
console.log(e)
}
})
module.exports = router;

View File

@ -0,0 +1,63 @@
const express = require('express');
const User = require("../../model/user.model");
const Group = require("../../model/group.model");
const Server = require("../../model/server.model");
memberService = require("../../services/members.service");
serverService = require("../../services/server.service");
var router = express.Router();
router.get("/", (req, res) => {
try {
Server.findAll().then((servers) => {
res.render('admin/servers', { "servers": servers })
});
} catch (e) {
console.log(e)
}
})
router.post("/add", (req, res) => {
try {
if (req.body.server_hostname && req.body.server_ip && req.body.server_username) {
serverService.addServer(req.body.server_hostname, req.body.server_ip, req.body.server_username).then((result) => {
res.redirect("/admin/servers")
})
} else {
res.redirect("/admin/servers")
}
} catch (e) {
console.log(e)
}
})
router.get("/delete/:server", (req, res) => {
try {
serverService.delServer(req.params.server).then((result) => {
res.redirect("/admin/servers")
})
} catch (e) {
console.log(e)
}
});
router.get("/:name", async (req, res) => {
try {
if (req.params.name === "new") {
res.render('admin/server_new')
} else {
console.log('a')
}
} catch(e){
console.log(e)
}
})
module.exports = router;

View File

@ -0,0 +1,71 @@
const express = require('express');
const User = require("../../model/user.model");
const Group = require("../../model/group.model");
const Key = require("../../model/key.model");
const keyService = require("../../services/keys.service");
groupService = require("../../services/group.service");
memberService = require("../../services/members.service");
userService = require("../../services/users.service");
var router = express.Router();
router.get("/",async (req, res) => {
try {
User.findAll().then((users) => {
res.render('admin/users', { "users": users})
})
} catch(e) {
console.log(e)
}
})
router.get("/delete/:userId", (req, res) => {
try {
userService.delUser(req.params.userId).then((result) => {
res.redirect("/admin/users")
})
} catch(e) {
console.log(e)
}
});
router.get("/:id", async (req, res) => {
try {
User.findOne({ where: { id: req.params.id } }).then((user) => {
Key.findAll({where: { "idOwner": user.id}}).then((keys) => {
res.render('admin/user_edit', { "keys": keys, "user": user})});
});
} catch(e) {
console.log(e)
}
})
router.get("/:id/deleteKey/:key", (req, res) => {
try {
keyService.delKey(req.params.key, req.params.id).then((result) => {
res.redirect("/admin/users/"+req.params.id)
})
} catch (e) {
console.log(e)
}
});
router.post("/:id/addKey", (req, res) => {
try {
if (req.body.key_content && req.body.key_name) {
keyService.addKey(req.body.key_content, req.body.key_name, req.params.id).then((result) => {
res.redirect("/admin/users/"+req.params.id)
})
} else {
res.redirect("/admin/users/"+req.params.id)
}
} catch(e) {
console.log(e)
}
})
module.exports = router;

View File

@ -10,17 +10,21 @@ router.get("/login", (req, res) => {
router.get("/callback", async (req, res) => {
const access_token = await authService.getToken(req.query.code);
const user = await authService.fetchUser(access_token);
if (user) {
await authService.syncUser(user);
req.session.access_token = access_token;
req.session.user = user;
req.session.loggedin = true;
req.session.admin = user.admin;
res.redirect("/");
} else {
res.send("An error occured");
try {
const access_token = await authService.getToken(req.query.code);
const user = await authService.fetchUser(access_token);
if (user) {
await authService.syncUser(user);
req.session.access_token = access_token;
req.session.user = user;
req.session.loggedin = true;
req.session.admin = user.admin;
res.redirect("/");
} else {
res.send("An error occured");
}
} catch (e) {
console.log(e)
}
});

View File

@ -13,28 +13,40 @@ router.get('*', (req, res, next) => {
});
router.post("/add", (req, res) => {
if (req.body.key_content && req.body.key_name) {
keyService.addKey(req.body.key_content, req.body.key_name, req.session.user.id).then((result) => {
try {
if (req.body.key_content && req.body.key_name) {
keyService.addKey(req.body.key_content, req.body.key_name, req.session.user.id).then((result) => {
res.redirect("/keys")
})
} else {
res.redirect("/keys")
})
} else {
res.redirect("/keys")
}
} catch (e) {
console.log(e)
}
})
router.get("/delete/:key", (req, res) => {
keyService.delKey(req.params.key, req.session.user.id).then((result) => {
res.redirect("/keys")
})
try {
keyService.delKey(req.params.key, req.session.user.id).then((result) => {
res.redirect("/keys")
})
} catch(e) {
console.log(e)
}
});
router.get("/", (req, res) => {
Key.findAll({where: {idOwner: req.session.user.id}}).then((keys) => {
res.render('keys', { "keys": keys })
})
try {
Key.findAll({where: {idOwner: req.session.user.id}}).then((keys) => {
res.render('keys', { "keys": keys })
})
} catch(e) {
console.log(e)
}
});
module.exports = router;

View File

@ -10,7 +10,7 @@ async function addGroup(name) {
} else {
if (name && regexp.test(name)) {
Group.create({
name: name,
name: name.toLowerCase(),
}).then((result) => {
console.log('Group ' + result.name + ' added to database')
});
@ -22,6 +22,8 @@ async function addGroup(name) {
});
}
async function delGroup(name) {
Group.findOne({where: { name: name}}).then((result) => {
if (result && regexp.test(name)) {

View File

@ -3,19 +3,17 @@ const Key = require('../model/key.model')
const regexp = /^\S*$/;
async function addKey(content, name, idOwner) {
const id_key = idOwner.toString() + name;
Key.findOne({where: { idKey: id_key}}).then((result) => {
Key.findOne({where: { idOwner: idOwner, name: name}}).then((result) => {
if (result) {
return false;
} else {
if (content && name && idOwner && regexp.test(name, idOwner, content)) {
Key.create({
idKey: id_key,
idOwner: idOwner,
content: content,
name: name,
name: name.toLowerCase(),
}).then((key) => {
console.log('key ' + key.idKey + ' added to database')
console.log('key for ' + key.idOwner + ' added to database')
});
} else {
return false;
@ -25,17 +23,13 @@ async function addKey(content, name, idOwner) {
});
}
async function delKey(id, idOwner) {
Key.findOne({where: { idKey: id}}).then((result) => {
if (result && regexp.test(id,idOwner)) {
if (result.idOwner !== idOwner) {
return false;
} else {
result.destroy()
.then(() => {
console.log('key ' + result.idKey + ' added to database')
});
}
async function delKey(name, idOwner) {
Key.findOne({where: { name: name, idOwner: idOwner}}).then((result) => {
if (result && regexp.test(name, idOwner)) {
result.destroy()
.then(() => {
console.log('key for ' + result.idOwner + ' deleted from database')
});
} else {
return false;

View File

@ -0,0 +1,48 @@
const Group = require('../model/group.model')
const Member = require('../model/member.model')
const User = require('../model/user.model')
const Server = require('../model/server.model')
const regexp_space = /^\S*$/;
const regexp_ip = /^((25[05]|2[04][09]|[01]?[09][09]?).(25[05]|2[04][09]|[01]?[09][09]?).(25[05]|2[04][09]|[01]?[09][09]?).(25[05]|2[04][09]|[01]?[09][09]?))|((([09A-Fa-f]{1,4}:){7}[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){6}:[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){5}:([09A-Fa-f]{1,4}:)?[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){4}:([09A-Fa-f]{1,4}:){0,2}[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){3}:([09A-Fa-f]{1,4}:){0,3}[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){2}:([09A-Fa-f]{1,4}:){0,4}[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){6}((b((25[05])|(1d{2})|(2[04]d)|(d{1,2}))b).){3}(b((25[05])|(1d{2})|(2[04]d)|(d{1,2}))b))|(([09A-Fa-f]{1,4}:){0,5}:((b((25[05])|(1d{2})|(2[04]d)|(d{1,2}))b).){3}(b((25[05])|(1d{2})|(2[04]d)|(d{1,2}))b))|(::([09A-Fa-f]{1,4}:){0,5}((b((25[05])|(1d{2})|(2[04]d)|(d{1,2}))b).){3}(b((25[05])|(1d{2})|(2[04]d)|(d{1,2}))b))|([09A-Fa-f]{1,4}::([09A-Fa-f]{1,4}:){0,5}[09A-Fa-f]{1,4})|(::([09A-Fa-f]{1,4}:){0,6}[09A-Fa-f]{1,4})|(([09A-Fa-f]{1,4}:){1,7}:))$/
async function addServer(hostname, ip, username) {
Server.findOne({where: { hostname: hostname}}).then((result) => {
if (result) {
return false;
} else {
if (hostname && ip && username && regexp_space.test(hostname, username) && regexp_ip.test(ip)) {
Server.create({
hostname: hostname.toLowerCase(),
ip: ip,
username: username.toLowerCase()
}).then((result) => {
console.log('Server ' + result.hostname + ' added to database')
});
} else {
return false;
}
}
});
}
async function delServer(hostname) {
Server.findOne({where: { hostname: hostname}}).then((result) => {
if (result && regexp_space.test(hostname)) {
result.destroy()
.then(() => {
console.log('server ' + result.hostname + ' deleted from database')
});
} else {
return false;
}
});
}
module.exports = {
addServer,
delServer
};

View File

@ -1,4 +1,8 @@
const User = require('../model/user.model')
const Key = require("../model/key.model");
const regexp = /^\S*$/;
async function userList(code) {
return await User.findAll()
@ -15,6 +19,23 @@ function makeAdmin(userId) {
});
}
async function delUser(id) {
User.findOne({where: { id: id}}).then((result) => {
if (result && regexp.test(id)) {
result.destroy()
.then(() => {
console.log('user ' + id + ' deleted from database')
});
} else {
return false;
}
});
}
module.exports = {
makeAdmin
makeAdmin,
delUser,
};

View File

@ -1,6 +1,6 @@
<%- include('../navbar', {active: "admin-groups"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4"><%= group.name %></h3>
<h3 class="text-dark mb-4"><a style="text-decoration: none" href="/admin/groups">Groups</a> / <%= group.name %></h3>
<div class="card shadow mb-5">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Group editing</p>

View File

@ -1,6 +1,6 @@
<%- include('../navbar', {active: "admin-groups"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4">New group: </h3>
<h3 class="text-dark mb-4"><a style="text-decoration: none" href="/admin/groups">Groups</a> / new </h3>
<div class="card shadow mb-5">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Group editing</p>

View File

@ -1,10 +1,10 @@
<%- include('../navbar', {active: "admin-groups"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4">Admin: Groups</h3>
<h3 class="text-dark mb-4">Groups</h3>
<div class="card shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">User list</p>
<p class="text-primary m-0 fw-bold">Group list</p>
</div>
<div class="card-body">
<div class="row">
@ -22,13 +22,13 @@
<th>Name</th>
<th>Member count</th>
<th>Server count</th>
<th style="text-align: right;">Actions</th>
<th></th>
</tr>
</thead>
<tbody>
<% groups.forEach(function (group) { %>
<tr>
<td><%= group.name %></td>
<td><a style="text-decoration: none" href="/admin/groups/<%= group.name %>"><%= group.name %></a></td>
<td><%= group.members.length %></td>
<td>undefined</td>
<td style="text-align: right;"><a class="btn btn-sm btn-primary" href="/admin/groups/<%= group.name %>"><i class="far fa-edit"></i></a> <a class="btn btn-sm btn-danger" href="/admin/groups/delete/<%= group.name %>"><i class="far fa-trash-alt"></i></a></td>

View File

@ -0,0 +1,25 @@
<%- include('../navbar', {active: "admin-servers"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4"><a style="text-decoration: none" href="/admin/groups">Servers</a> / new </h3>
<div class="card shadow mb-5">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Server editing</p>
</div>
<form method="POST" action="/admin/servers/add/">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="mb-3"><label class="form-label"><strong>Hostname</strong></label><input class="form-control" placeholder="exemple.accessgate" type="text" name="server_hostname"></div>
<div class="mb-3"><label class="form-label"><strong>IP Address</strong></label><input class="form-control" placeholder="127.0.0.1" type="text" name="server_ip"></div>
<div class="mb-3"><button class="btn btn-primary btn-sm" type="submit">Create server</button></div>
</div>
<div class="col-md-6">
<div class="mb-3"><label class="form-label"><strong>User</strong></label><input class="form-control" placeholder="root" type="text" name="server_username"></div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<%- include('../footer'); %>

53
views/admin/servers.ejs Normal file
View File

@ -0,0 +1,53 @@
<%- include('../navbar', {active: "admin-servers"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4">Servers</h3>
<div class="card shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Server list</p>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 text-nowrap">
<div id="dataTable_length" class="dataTables_length" aria-controls="dataTable"><a class="btn btn-primary" href="/admin/servers/new" data-toggle="modal" >New server</a></div>
</div>
<div class="col-md-6">
<div class="text-md-end dataTables_filter" id="dataTable_filter"><label class="form-label"><input type="search" class="form-control form-control-sm" aria-controls="dataTable" placeholder="Search"></label></div>
</div>
</div>
<div class="table-responsive table mt-2" id="dataTable" role="grid" aria-describedby="dataTable_info">
<table class="table my-0" id="dataTable">
<thead>
<tr>
<th>Hostname</th>
<th>IP</th>
<th>User</th>
<th>Last pull</th>
<th></th>
</tr>
</thead>
<tbody>
<% servers.forEach(function (server) { %>
<tr>
<td><%= server.hostname %></td>
<td><%= server.ip %></td>
<td><%= server.username %></td>
<td><%= server.lastPull %></td>
<td style="text-align: right;"> <a class="btn btn-sm btn-danger" href="/admin/servers/delete/<%= server.hostname %>"><i class="far fa-trash-alt"></i></a></td>
</tr>
<% }) %>
</tbody>
<tfoot>
<tr></tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
<%- include('../footer'); %>

48
views/admin/user_edit.ejs Normal file
View File

@ -0,0 +1,48 @@
<%- include('../navbar', {active: "admin-users"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4"><a style="text-decoration: none" href="/admin/users/">Users</a> / <%= user.login %></h3></h3>
<div class="card shadow mb-5">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">SSH Keys</p>
</div>
<div class="card-body">
<div class="row">
<div class="col">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Key</th>
<th></th>
</tr>
</thead>
<tbody>
<% keys.forEach(function (key) { %>
<tr>
<td><%= key.name %></td>
<td><%= key.content %></td>
<td style="text-align: right;"><a class="btn btn-sm btn-danger" href="/admin/users/<%= user.id %>/deleteKey/<%= key.name %>"><i class="far fa-trash-alt"></i></button></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
<div class="col-md-6">
<form method="POST" action="/admin/users/<%= user.id %>/addKey/">
<div class="mb-3"><label class="form-label"><strong>Name</strong></label><input class="form-control" type="text" name="key_name"></div>
<div class="mb-3"><label class="form-label"><strong>Key</strong></label><textarea class="form-control" name="key_content" rows="2"></textarea></div>
<div class="mb-3"></div>
<div class="mb-3"><button class="btn btn-primary btn-sm" type="submit">Add key</button></div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<%- include('../footer'); %>

View File

@ -1,6 +1,6 @@
<%- include('../navbar', {active: "admin-users"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4">Admin: Users</h3>
<h3 class="text-dark mb-4">Users</h3>
<div class="card shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">User list</p>
@ -22,10 +22,11 @@
<table class="table my-0" id="tableEnabled">
<thead>
<tr>
<th>Username</th>
<th>username</th>
<th>id</th>
<th>Admin</th>
<th>Last login</th>
<th>admin</th>
<th>updated</th>
<th></th>
</tr>
</thead>
<tbody>
@ -34,8 +35,9 @@
<td><img class="rounded-circle me-2" width="30" height="30" src="<%= user.avatar %>"><%= user.login %></td>
<td><%= user.id %></td>
<td><%= user.admin %></td>
<td><%= user.updatedAt %></td>
<td style="text-align: right;"><a class="btn btn-sm btn-primary" href="/admin/users/<%= user.id %>"><i class="fas fa-key"></i></a> <a class="btn btn-sm btn-danger" href="/admin/users/delete/<%= user.id %>"><i class="far fa-trash-alt"></i></a></td>
</tr>
<% }) %>
</tbody>

View File

@ -10,7 +10,7 @@
<div class="row align-items-center no-gutters">
<div class="col me-2">
<div class="text-uppercase text-primary fw-bold text-xs mb-1"><span>my keys</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>1</span></div>
<div class="text-dark fw-bold h5 mb-0"><span><%= stats.keys %></span></div>
</div>
<div class="col-auto"><i class="fas fa-key fa-2x text-gray-300"></i></div>
</div>
@ -23,7 +23,7 @@
<div class="row align-items-center no-gutters">
<div class="col me-2">
<div class="text-uppercase text-success fw-bold text-xs mb-1"><span>my authorized servers</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>5</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>undefined</span></div>
</div>
<div class="col-auto"><i class="fas fa-hdd fa-2x text-gray-300"></i></div>
</div>
@ -38,7 +38,7 @@
<div class="text-uppercase text-info fw-bold text-xs mb-1"><span>my groups</span></div>
<div class="row g-0 align-items-center">
<div class="col-auto">
<div class="text-dark fw-bold h5 mb-0 me-3"><span>2</span></div>
<div class="text-dark fw-bold h5 mb-0 me-3"><span><%= stats.groups %></span></div>
</div>
</div>
</div>
@ -53,7 +53,7 @@
<div class="row align-items-center no-gutters">
<div class="col me-2">
<div class="text-uppercase text-warning fw-bold text-xs mb-1"><span>Pending requests</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>18</span></div>
<div class="text-dark fw-bold h5 mb-0"><span>0</span></div>
</div>
<div class="col-auto"><i class="fas fa-comments fa-2x text-gray-300"></i></div>
</div>

View File

@ -1,40 +1,6 @@
<%- include('navbar', {active: "keys"}); %>
<div class="container-fluid">
<h3 class="text-dark mb-4">Keys management</h3>
<div class="row mb-3">
<div class="col-lg-8">
<div class="row mb-3 d-none">
<div class="col">
<div class="card text-white bg-primary shadow">
<div class="card-body">
<div class="row mb-2">
<div class="col">
<p class="m-0">Peformance</p>
<p class="m-0"><strong>65.2%</strong></p>
</div>
<div class="col-auto"><i class="fas fa-rocket fa-2x"></i></div>
</div>
<p class="text-white-50 small m-0"><i class="fas fa-arrow-up"></i>&nbsp;5% since last month</p>
</div>
</div>
</div>
<div class="col">
<div class="card text-white bg-success shadow">
<div class="card-body">
<div class="row mb-2">
<div class="col">
<p class="m-0">Peformance</p>
<p class="m-0"><strong>65.2%</strong></p>
</div>
<div class="col-auto"><i class="fas fa-rocket fa-2x"></i></div>
</div>
<p class="text-white-50 small m-0"><i class="fas fa-arrow-up"></i>&nbsp;5% since last month</p>
</div>
</div>
</div>
</div>
</div>
</div>
<h3 class="text-dark mb-4"><a style="text-decoration: none" href="/">Dashboard</a> / keys</h3></h3>
<div class="card shadow mb-5">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">SSH Keys</p>
@ -58,7 +24,7 @@
<td><%= key.content %></td>
<td style="text-align: right;"><a class="btn btn-sm btn-danger" href="/keys/delete/<%= key.idKey %>"><i class="far fa-trash-alt"></i></button></td>
<td style="text-align: right;"><a class="btn btn-sm btn-danger" href="/keys/delete/<%= key.name %>"><i class="far fa-trash-alt"></i></button></td>
</tr>
<% }) %>