mirror of
https://github.com/koush/scrypted.git
synced 2026-02-07 16:02:13 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5028fb812d | ||
|
|
2db4e2579f | ||
|
|
b339ca6cd2 | ||
|
|
f100999cb1 |
@@ -10,3 +10,6 @@ scrypted.db.bak
|
||||
__pycache__
|
||||
.venv
|
||||
.vscode
|
||||
tsconfig.json
|
||||
test
|
||||
scripts
|
||||
|
||||
4
server/package-lock.json
generated
4
server/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.7.43",
|
||||
"version": "0.7.45",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.7.43",
|
||||
"version": "0.7.45",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.10",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.7.44",
|
||||
"version": "0.7.45",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.10",
|
||||
|
||||
@@ -279,6 +279,15 @@ export class DeviceManagerImpl implements DeviceManager {
|
||||
}
|
||||
}
|
||||
|
||||
function toStorageString(value: any) {
|
||||
if (value === null)
|
||||
return 'null';
|
||||
if (value === undefined)
|
||||
return 'undefined;'
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
class StorageImpl implements Storage {
|
||||
api: PluginAPI;
|
||||
[name: string]: any;
|
||||
@@ -293,17 +302,17 @@ class StorageImpl implements Storage {
|
||||
];
|
||||
private static indexedHandler: ProxyHandler<StorageImpl> = {
|
||||
get(target, property) {
|
||||
if (StorageImpl.allowedMethods.includes(property.toString())) {
|
||||
const prop = property.toString();
|
||||
const f = target[property.toString()];
|
||||
if (prop === 'length')
|
||||
const keyString = property.toString();
|
||||
if (StorageImpl.allowedMethods.includes(keyString)) {
|
||||
const f = target[keyString];
|
||||
if (keyString === 'length')
|
||||
return f;
|
||||
return f.bind(target);
|
||||
}
|
||||
return target.getItem(property.toString());
|
||||
return target.getItem(toStorageString(property));
|
||||
},
|
||||
set(target, property, value): boolean {
|
||||
target.setItem(property.toString(), value);
|
||||
target.setItem(toStorageString(property), value);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -351,6 +360,8 @@ class StorageImpl implements Storage {
|
||||
this.api.setStorage(this.nativeId, this.storage);
|
||||
}
|
||||
setItem(key: string, value: string): void {
|
||||
key = toStorageString(key);
|
||||
value = toStorageString(value);
|
||||
if (this.storage[this.prefix + key] === value)
|
||||
return;
|
||||
this.storage[this.prefix + key] = value;
|
||||
|
||||
@@ -94,6 +94,8 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
|
||||
super(app);
|
||||
this.datastore = datastore;
|
||||
this.app = app;
|
||||
// ensure that all the users are loaded from the db.
|
||||
this.usersService.getAllUsers();
|
||||
|
||||
this.pluginHosts.set('python', (_, pluginId, options) => new PythonRuntimeWorker(pluginId, options));
|
||||
this.pluginHosts.set('node', (mainFilename, pluginId, options) => new NodeForkWorker(mainFilename, pluginId, options));
|
||||
|
||||
@@ -212,7 +212,7 @@ async function start(mainFilename: string, options?: {
|
||||
const sha = hash.digest().toString('hex');
|
||||
|
||||
if (checkHash === sha) {
|
||||
const userToken = validateToken(tokenPart);
|
||||
const userToken = checkValidUserToken(tokenPart);
|
||||
if (userToken) {
|
||||
res.locals.username = userToken.username;
|
||||
res.locals.aclId = userToken.aclId;
|
||||
@@ -420,19 +420,23 @@ async function start(mainFilename: string, options?: {
|
||||
return req.secure ? 'login_user_token' : 'login_user_token_insecure';
|
||||
};
|
||||
|
||||
const validateToken = (token: string) => {
|
||||
const checkValidUserToken = (token: string) => {
|
||||
if (!token)
|
||||
return;
|
||||
try {
|
||||
return UserToken.validateToken(token);
|
||||
const userToken = UserToken.validateToken(token);
|
||||
if (scrypted.usersService.users.has(userToken.username))
|
||||
return userToken;
|
||||
}
|
||||
catch (e) {
|
||||
console.warn('invalid token', e.message);
|
||||
// console.warn('invalid token', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
const getSignedLoginUserTokenRawValue = (req: Request<any>) => req.signedCookies[getLoginUserToken(req)] as string;
|
||||
const getSignedLoginUserToken = (req: Request<any>) => validateToken(getSignedLoginUserTokenRawValue(req));
|
||||
const getSignedLoginUserToken = (req: Request<any>) => {
|
||||
const token = req.signedCookies[getLoginUserToken(req)] as string;
|
||||
return checkValidUserToken(token)
|
||||
};
|
||||
|
||||
app.get('/logout', (req, res) => {
|
||||
res.clearCookie(getLoginUserToken(req));
|
||||
@@ -621,10 +625,9 @@ async function start(mainFilename: string, options?: {
|
||||
|
||||
// cookie auth
|
||||
try {
|
||||
const login_user_token = getSignedLoginUserTokenRawValue(req);
|
||||
if (!login_user_token)
|
||||
const userToken = getSignedLoginUserToken(req);
|
||||
if (!userToken)
|
||||
throw new Error('Not logged in.');
|
||||
const userToken = UserToken.validateToken(login_user_token);
|
||||
|
||||
res.send({
|
||||
...createTokens(userToken),
|
||||
|
||||
@@ -3,14 +3,32 @@ import { ScryptedRuntime } from "../runtime";
|
||||
import crypto from 'crypto';
|
||||
|
||||
export class UsersService {
|
||||
users = new Map<string, ScryptedUser>();
|
||||
usersPromise: Promise<ScryptedUser[]>;
|
||||
|
||||
constructor(public scrypted: ScryptedRuntime) {
|
||||
}
|
||||
|
||||
async getAllUsers() {
|
||||
const users: ScryptedUser[] = [];
|
||||
for await (const user of this.scrypted.datastore.getAll(ScryptedUser)) {
|
||||
users.push(user);
|
||||
private async ensureUsersPromise() {
|
||||
if (!this.usersPromise) {
|
||||
this.usersPromise = (async() => {
|
||||
const users = new Map<string, ScryptedUser>();
|
||||
for await (const user of this.scrypted.datastore.getAll(ScryptedUser)) {
|
||||
users.set(user._id, user);
|
||||
}
|
||||
this.users = users;
|
||||
return [...this.users.values()];
|
||||
})();
|
||||
}
|
||||
return this.usersPromise;
|
||||
}
|
||||
|
||||
private updateUsersPromise() {
|
||||
this.usersPromise = Promise.resolve([...this.users.values()]);
|
||||
}
|
||||
|
||||
async getAllUsers() {
|
||||
const users = await this.ensureUsersPromise();
|
||||
|
||||
return users.map(user => ({
|
||||
username: user._id,
|
||||
@@ -19,19 +37,31 @@ export class UsersService {
|
||||
}
|
||||
|
||||
async removeUser(username: string) {
|
||||
await this.ensureUsersPromise();
|
||||
|
||||
await this.scrypted.datastore.removeId(ScryptedUser, username);
|
||||
this.users.delete(username);
|
||||
this.updateUsersPromise();
|
||||
}
|
||||
|
||||
async removeAllUsers() {
|
||||
await this.ensureUsersPromise();
|
||||
|
||||
await this.scrypted.datastore.removeAll(ScryptedUser);
|
||||
this.users.clear();
|
||||
this.updateUsersPromise();
|
||||
}
|
||||
|
||||
async addUser(username: string, password: string, aclId: string) {
|
||||
await this.ensureUsersPromise();
|
||||
|
||||
const user = new ScryptedUser();
|
||||
user._id = username;
|
||||
user.aclId = aclId;
|
||||
setScryptedUserPassword(user, password, Date.now());
|
||||
await this.scrypted.datastore.upsert(user);
|
||||
this.users.set(username, user);
|
||||
this.updateUsersPromise();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ export class UserToken {
|
||||
}
|
||||
|
||||
static validateToken(token: string): UserToken {
|
||||
if (!token)
|
||||
throw new Error('Token not found.');
|
||||
|
||||
let json: {
|
||||
u: string,
|
||||
a: string,
|
||||
|
||||
Reference in New Issue
Block a user