1
0
mirror of https://github.com/Foltik/Shimapan synced 2025-01-06 00:08:25 -05:00

Merge pull request #10 from Foltik/mean

Mean
This commit is contained in:
Jack Foltz 2017-10-21 18:10:27 -04:00 committed by GitHub
commit 1f56424d74
10 changed files with 337 additions and 54 deletions

View File

@ -200,35 +200,173 @@ body {
user-select: none;
}
.modal {
.key-name {
color: #2a9fd6;
font-family: 'Roboto Mono', monospace;
}
pre {
overflow: auto;
line-height: 1.7em;
font-family: 'Roboto Mono', monospace;
border: 1px solid #666;
border-radius: 4px;
display: block;
padding: 10px;
font-size: 14px;
margin: 10px 0;
background: #222;
color: #2a9fd6;
}
.modal,
.modal-box {
z-index: 900;
}
.modal-sandbox {
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: transparent;
}
.modal {
display: none;
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgb(0,0,0);
background: rgba(0,0,0,.8);
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-box {
position: relative;
width: 80%;
max-width: 700px;
margin: 60px auto;
animation-name: modalbox;
animation-duration: .3s;
animation-timing-function: ease;
}
#createKey {
max-width: 920px;
}
.modal-header {
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
border: 2px solid #2a9fd6;
border-radius: 8px 8px 0 0;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 20px 40px;
background: #000;
color: #ffffff;
}
.modal-body {
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
border: 2px solid #2a9fd6;
border-top: none;
background: #000;
padding: 30px;
}
.modal-footer {
margin: auto;
display: flex;
justify-content: flex-end;
border: 2px solid #2a9fd6;
border-radius: 0 0 8px 8px;
border-top: none;
background: #000;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
}
.close-modal {
text-align: right;
font-size: 24px;
cursor: pointer;
}
@keyframes modalbox {
0% {
top: -250px;
opacity: 0;
}
100% {
top: 0;
opacity: 1;
}
}
button {
margin-left: 20px;
color: #d3d3d3;
background: #000;
border: 2px solid #2a9fd6;
border-radius: 5px;
padding: 10px;
cursor: pointer;
transition: background-color 0.25s;
}
button:hover {
color: #fff;
background-color: #2a9fd6;
text-decoration: none;
outline: none;
}
::-moz-focus-inner {
outline: none;
}
.btn-del {
text-transform: uppercase;
border: 2px solid #ff6666;
color: #ccc;
}
.btn-del:hover {
background-color: #ff6666;
}
em {
text-transform: uppercase;
font-weight: bold;
}
#identifier {
font-size: 14px;
background: #222;
color: #d3d3d3;
border: 1px solid #666;
border-radius: 4px;
padding: 10px;
margin: 10px 0;
}
th {
text-transform: uppercase;
font-weight: bold;
padding: 10px;
}
td {
padding: 10px;
}
td input {
vertical-align: middle;
}
td label {
margin-bottom: 2px;
padding-left: 3px;
}

View File

@ -1,10 +1,78 @@
var angular = require('angular');
angular.module('ApiCtrl', ['ApiSvc', 'AuthSvc']).controller('ApiController', ['$scope', 'ApiService', 'AuthService', function($scope, ApiService, AuthService) {
$scope.getKeys = function() {
ApiService.getAll(function(keys) {
angular.module('ApiCtrl', ['ApiSvc', 'AuthSvc']).controller('ApiController', ['$scope', 'ApiService', 'AuthService', function ($scope, ApiService, AuthService) {
function splitScope(scope) {
var res = {};
for (var i in scope) {
var perm = scope[i];
var prefix = perm.substr(0, perm.indexOf('.'));
var postfix = perm.substr(perm.indexOf('.') + 1);
if (!res[prefix]) res[prefix] = [];
res[prefix].push({name: postfix});
}
return res;
}
$scope.checkCkPerm = function(prefix, perm) {
var index = $scope.scopeObj[prefix].indexOf(perm);
if ($scope.scopeObj[prefix][index].isChecked) {
$scope.ckScope.push(prefix + '.' + perm.name);
} else {
var index = $scope.ckScope.indexOf(prefix + '.' + perm.name);
$scope.ckScope.splice(index, 1);
}
};
$scope.parseScope = function () {
AuthService.currentUser(function (res) {
$scope.scopeObj = splitScope(res.scope);
$scope.ckScope = [];
})
};
$scope.getKeys = function () {
ApiService.getAll(function (keys) {
$scope.keys = keys;
});
console.log($scope.keys);
};
$scope.hideNewKey = function () {
$scope.nModalShow = false;
};
$scope.showNewKey = function () {
$scope.nModalShow = true;
};
$scope.hideKeyInfo = function () {
$scope.kModalShow = false;
};
$scope.showKeyInfo = function (key) {
$scope.kModalShow = true;
$scope.currKey = key;
$scope.currKey.scopeObj = splitScope($scope.currKey.scope);
};
$scope.deleteKey = function (key) {
ApiService.deleteKey(key, function () {
var index = $scope.keys.indexOf(key);
$scope.keys.splice(index, 1);
$scope.hideKeyInfo();
$scope.currKey = {};
});
};
$scope.createKey = function () {
if ($scope.ckScope.length === 0 || !$scope.ckIdentifier)
return;
ApiService.createKey({
identifier: $scope.ckIdentifier,
scope: JSON.stringify($scope.ckScope)
}, function (res) {
if (res.key) {
$scope.hideNewKey();
$scope.getKeys();
}
});
}
}]);

View File

@ -19,4 +19,38 @@ angular.module('ApiSvc', []).service('ApiService', ['$http', '$window', function
cb(res.data);
});
};
this.deleteKey = function (key, cb) {
$http({
method: 'POST',
url: '/api/keys/delete',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: {key: key.key}
}).then(function (res) {
cb(res.data);
});
};
this.createKey = function (key, cb) {
$http({
method: 'POST',
url: '/api/keys/create',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: key
}).then(function(res) {
cb(res.data);
});
};
}]);

View File

@ -38,6 +38,7 @@ router.post('/register', function (req, res, next) {
req.session.save(function(err) {
if (err) return next(err);
useInvite(req.body.invite, req.body.username);
req.session.username = req.body.username;
res.status(200).json({'message': 'Registered.'});
});
});
@ -55,6 +56,7 @@ router.post('/login', function (req, res, next) {
if (!user) return res.status(401).json({'message': info});
req.logIn(user, function(err) {
if (err) return next(err);
req.session.username = user;
res.status(200).json({'message': 'Logged in.'});
});
})(req, res, next);

View File

@ -64,4 +64,11 @@ router.get('/get', function (req, res, next) {
})
});
router.post('/delete', function(req, res, next) {
Key.deleteOne({key: req.body.key}, function(err) {
if (err) next(err);
else res.status(200).json({'message': 'Successfully deleted.'});
});
});
module.exports = router;

View File

@ -12,10 +12,10 @@ var fs = require('fs');
var path = require('path');
var requireLogin = function(req, res, next) {
if (!req.session.passport.user)
res.redirect('/login');
if (!req.session || !req.session.passport)
return res.redirect('/login');
else
next();
return next();
};
module.exports = function(app) {

9
package-lock.json generated
View File

@ -942,15 +942,6 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-parser": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz",
"integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=",
"requires": {
"cookie": "0.3.1",
"cookie-signature": "1.0.6"
}
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",

View File

@ -9,7 +9,6 @@
"body-parser": "^1.18.2",
"config": "^1.26.2",
"connect-mongo": "^2.0.0",
"cookie-parser": "^1.4.3",
"event-stream": "^3.3.4",
"express": "^4.16.2",
"express-sanitizer": "^1.0.2",

View File

@ -1,30 +1,76 @@
<div class="inner" ng-controller="ApiController" ng-init="currKey={};showModal=false;getKeys()">
<div class="inner" ng-controller="ApiController" ng-init="getKeys();parseScope()">
<div class="keys">
<div class="key" ng-repeat="key in keys">
<div class="key" ng-repeat="key in keys" ng-click="$parent.showKeyInfo(key)">
<i class="fa fa-key"></i>
<span>{{key.identifier}}</span>
</div>
<div class="key add-key" ng-hide="keys.length >= 10">
<div class="key add-key" ng-hide="keys.length >= 10" ng-click="showNewKey()">
<i class="fa fa-plus"></i>
<span>Create</span>
</div>
</div>
<div class="modal" ng-show="showModal==true">
<div class="modal-header">
<button class="close" type="button"></button>
<h4 class="modal-title">API Key</h4>
<div class="modal" style="{{kModalShow?'display:block':'display:none'}}">
<div class="modal-sandbox" ng-click="hideKeyInfo()"></div>
<div class="modal-box">
<div class="modal-header">
<h1>Key Info:&emsp;<span class="key-name">{{currKey.identifier}}</span></h1>
<div class="close-modal" ng-click="hideKeyInfo()"><i class="fa fa-times"></i></div>
</div>
<div class="modal-body">
<p>API Key:</p>
<pre>{{currKey.key}}</pre>
<br/>
<p>This key can be used with any 3rd party program or service to upload to and manage your account
with Shimapan.</p>
<p>For example, it can be used in a bash script to upload from the command line:</p>
<pre>APIKEY=[Your API Key Here]<br/>URL=$(curl -s -F "apikey=$APIKEY" -F "file=@$1" https://shimapan.rocks/api/upload | grep url | awk '{print $2}')<br/>echo $URL | tr -d '[\\\,"\n]'</pre>
<br/>
<p>Key Permissions:</p>
<table>
<tr ng-repeat="(prefix, perms) in currKey.scopeObj">
<th>{{prefix}}:</th>
<td ng-repeat="perm in perms">
<span ng-bind="perm.name"></span>
</td>
</tr>
</table>
<br/>
<p>If your key is compromised, it can be used to upload and modify your account without your knowledge.
If it is lost or compromised, you can delete the key below, but be warned that this <em>cannot</em>
be undone.</p>
</div>
<div class="modal-footer">
<button class="btn-del" ng-click="deleteKey(currKey)">Delete Key</button>
<button class="btn-close" ng-click="hideKeyInfo()">Close</button>
</div>
</div>
<div class="modal-body modal-key">
<p>API Key:</p>
<pre class="code">{{currKey.code}}</pre>
<p>Use this key with your preferred method of utilizing the Shimapan API.</p>
<p>Example with cURL:</p>
<pre class="code"></pre>
<div id="qr"></div>
</div>
<div class="modal-footer">
<button class="btn-delete" type="button"></button>
<button class="btn-back" type="button"></button>
</div>
<div class="modal" style="{{nModalShow?'display:block':'display:none'}}">
<div class="modal-sandbox" ng-click="hideNewKey()"></div>
<div class="modal-box" id="createKey">
<div class="modal-header">
<h1>Create a Key</h1>
<div class="close-modal" ng-click="hideNewKey()"><i class="fa fa-times"></i></div>
</div>
<div class="modal-body">
<p>Identifier to describe the purpose/use of this key:</p>
<input id="identifier" placeholder="Identifier" class="form-control" type="text" ng-model="ckIdentifier"/>
<br/>
<p>Permissions the key should have:</p>
<table>
<tr ng-repeat="(prefix, perms) in scopeObj">
<th>{{prefix}}:</th>
<td ng-repeat="perm in perms">
<input type="checkbox" name="{{perm.name}}" ng-model="perm.isChecked" ng-change="checkCkPerm(prefix, perm)"/>
<label for="{{perm.name}}" ng-bind="perm.name"></label>
</td>
</tr>
</table>
</div>
<div class="modal-footer">
<button ng-click="createKey()">Create</button>
<button ng-click="hideNewKey()">Cancel</button>
</div>
</div>
</div>
</div>

View File

@ -4,7 +4,6 @@ var methodOverride = require('method-override');
var mongoose = require('mongoose');
var morgan = require('morgan');
var passport = require('passport');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var sanitizer = require('express-sanitizer');
var helmet = require('helmet');
@ -45,7 +44,6 @@ app.use(session({
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.json({ type: 'application/*+json' }))
app.use(bodyParser.urlencoded({ extended: true }));