add user settings, add checkbox to share data on

/useradmin/overview page
pull/4/head
AdamSBlack 2022-05-01 23:01:13 +01:00
parent 0679c44b08
commit 21067730dd
No known key found for this signature in database
GPG Key ID: E66E51A97D150E28
12 changed files with 2092 additions and 344 deletions

2221
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,7 @@
"sanitize": "^2.1.0",
"sequelize": "^6.17.0",
"simple-oauth2": "^4.3.0",
"spm-agent-nodejs": "^4.1.4",
"sqlite": "^4.0.25",
"sqlite3": "^5.0.2",
"supertest": "^6.2.2",

View File

@ -45,6 +45,11 @@ const Accounts = sequelize.define('accounts', {
allowNull: true,
type: DataTypes.BOOLEAN,
},
research_enabled: {
allowNull: false,
type: DataTypes.BOOLEAN,
defaultValue: false,
},
}, {
timestamps: false,
});

View File

@ -1,48 +0,0 @@
import { DataTypes } from 'sequelize';
import sequelize from './orm';
const AthenaActionLog = sequelize.define('athena_action_log', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
account_id: {
allowNull: true,
type: DataTypes.INTEGER,
},
device_id: {
allowNull: true,
type: DataTypes.INTEGER,
},
action: {
allowNull: true,
type: DataTypes.TEXT,
},
user_ip: {
allowNull: true,
type: DataTypes.TEXT,
},
device_ip: {
allowNull: true,
type: DataTypes.TEXT,
},
meta: {
allowNull: true,
type: DataTypes.TEXT,
},
created_at: {
allowNull: true,
type: DataTypes.BIGINT,
},
dongle_id: {
allowNull: true,
type: DataTypes.TEXT,
},
}, {
timestamps: false,
});
export default AthenaActionLog;

View File

@ -1,40 +0,0 @@
import { DataTypes } from 'sequelize';
import sequelize from './orm';
const AthenaReturnedData = sequelize.define('athena_returned_data', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
device_id: {
allowNull: true,
type: DataTypes.INTEGER,
},
type: {
allowNull: true,
type: DataTypes.TEXT,
},
data: {
allowNull: true,
type: DataTypes.TEXT,
},
created_at: {
allowNull: true,
type: DataTypes.TEXT,
},
uuid: {
allowNull: false,
type: DataTypes.TEXT,
},
resolved_at: {
allowNull: true,
type: DataTypes.INTEGER,
},
}, {
timestamps: false,
});
export default AthenaReturnedData;

View File

@ -1,40 +0,0 @@
import { DataTypes } from 'sequelize';
import sequelize from './orm';
const DeviceAuthorisedUsers = sequelize.define('device_authorised_users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
account_id: {
allowNull: false,
type: DataTypes.INTEGER,
},
device_id: {
allowNull: true,
type: DataTypes.INTEGER,
},
athena: {
allowNull: true,
type: DataTypes.BOOLEAN,
},
unpair: {
allowNull: true,
type: DataTypes.BOOLEAN,
},
view_drives: {
allowNull: true,
type: DataTypes.BOOLEAN,
},
created_at: {
allowNull: true,
type: DataTypes.BIGINT,
},
}, {
timestamps: false,
});
export default DeviceAuthorisedUsers;

View File

@ -1,40 +0,0 @@
import { DataTypes } from 'sequelize';
import sequelize from './orm';
const OAuthAccounts = sequelize.define('oauth_accounts', {
id: {
id: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
account_id: {
allowNull: false,
type: DataTypes.INTEGER,
},
email: {
allowNull: false,
type: DataTypes.TEXT,
},
created: {
allowNull: true,
type: DataTypes.TIME,
},
last_used: {
allowNull: true,
type: DataTypes.CHAR,
},
refresh: {
allowNull: true,
type: DataTypes.TEXT,
},
provider: {
allowNull: true,
type: DataTypes.TEXT,
},
}, {
timestamps: false,
});
export default OAuthAccounts;

View File

@ -1,4 +1,3 @@
// TODO move everythijng away from this dumb intertwined style
import authentication from './authentication';
import { Accounts } from '../../models';

View File

@ -67,6 +67,8 @@ async function changePassword(account, newPassword, oldPassword) {
async function getAuthenticatedAccount(req) {
const sessionJWT = req.cookies.jwt;
if ((!sessionJWT || sessionJWT.expires <= Date.now())) {
console.log('Authentication - expired JWT session provided', sessionJWT);
return null;
}
@ -75,14 +77,18 @@ async function getAuthenticatedAccount(req) {
async function getAccountFromJWT(jwt, limitData = true) {
let token;
console.log(jwt);
try {
token = jsonwebtoken.verify(jwt, process.env.APP_SALT);
} catch (err) {
console.log(jwt, 'bad jwt');
return null;// {success: false, msg: 'BAD_JWT'}
}
if (!token || !token.accountId) {
console.log(jwt, 'bad token');
return null; // {success: false, badToken: true}
}
@ -97,6 +103,8 @@ async function getAccountFromJWT(jwt, limitData = true) {
const account = await Accounts.findOne(query);
if (!account || !account.dataValues) {
console.log(jwt, 'invalid');
return null; // {success: false, isInvalid: true}
}
@ -110,6 +118,8 @@ async function getAccountFromJWT(jwt, limitData = true) {
}
if (!account || account.banned) {
console.log(jwt, 'banned');
return null; // {success: false, isBanned: true}
}
return account;

View File

@ -7,6 +7,7 @@ export const getAccount = async (req, res, next) => {
export const requireAuthenticated = async (req, res, next) => {
const account = await authenticationController.getAuthenticatedAccount(req);
console.log(account);
if (!account) {
res.status(401).json({
success: false,

View File

@ -5,6 +5,7 @@ import admin from './admin';
import auth from './auth';
import devices from './devices';
import useradmin from './useradmin';
import userSettings from './user/settings';
// /api
const router = express.Router();
@ -13,6 +14,9 @@ router.use('/admin', admin);
router.use('/auth', auth);
router.use('/devices', devices);
router.use('/useradmin', useradmin);
router.use('/user/settings', userSettings);
console.log(userSettings);
// TODO: setup oauth and twofactor endpoints
// app.use(routers.oauthAuthenticator);

View File

@ -214,7 +214,30 @@ router.get('/overview', requireAuthenticated, runAsyncWrapper(async (req, res) =
<b>Account:</b> #${account.id}<br>
<b>Email:</b> ${account.email}<br>
<b>Created:</b> ${helperController.formatDate(account.created)}<br><br>
<b>User Settings</b>
<br>
<input type="checkbox" id="share-data" name="sharedata"
checked>
<label for="scales">Share drives for community model development</label><br>
<script>
const selectElement = document.querySelector('#share-data');
fetch('/api/user/settings/research')
.then(response => response.json())
.then((data) => {
if (data.success) {
selectElement.checked = data.data.research_enabled
}
});
selectElement.addEventListener('change', (event) => {
fetch('/api/user/settings/research/'+event.target.checked, {
method: 'PATCH'})
});
</script>
<br><br>
<b>Devices:</b><br>
<table border=1 cellpadding=2 cellspacing=2>
<tr><th>dongle_id</th><th>device_type</th><th>created</th><th>last_ping</th><th>storage_used</th></tr>
`;
@ -230,6 +253,8 @@ router.get('/overview', requireAuthenticated, runAsyncWrapper(async (req, res) =
</tr>`;
});
response += `</table>
<br>
<hr/>