Skip to content

Commit

Permalink
[2/2] sauce: add ssh keydrop feature
Browse files Browse the repository at this point in the history
TODO: Add bootstrap/SASS validation for better UX.
  • Loading branch information
makinbacon21 committed Feb 26, 2024
1 parent 443ef5a commit d0f4b62
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 3 deletions.
26 changes: 25 additions & 1 deletion src/controllers/accountController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { v4 as uuidv4 } from 'uuid';
import { HttpException } from '../error/httpException';
import { mailTransporter } from '../integration/email';
import { ldapClient } from '../integration/ldap';
import { modifyForwardFile } from '../integration/localAgent';
import { modifyForwardFile, modifySSHFile } from '../integration/localAgent';
import { PasswordResetRequest, PasswordResetRequestModel, TaskModel } from '../integration/models';
import { generateEmail } from '../util/emailTemplates';
import { sendTaskNotification } from '../util/emailUtils';
Expand Down Expand Up @@ -308,3 +308,27 @@ export const configureEmailForwarding = async (

logger.info(`Updated email forwarding for ${user.uid} to ${JSON.stringify(config)}`);
};

const sshKey = () =>
jf
.string()
.pattern(/^(ssh-rsa AAAAB3NzaC1yc2|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzOD|ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1Mj|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|ssh-dss AAAAB3NzaC1kc3)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?(\n|$)/)
.required();

/**
*/
export class SSHConfig {
@sshKey()
keys: string;
}

export const configureSSH = async (
user: any,
config: SSHConfig,
): Promise<void> => {
logger.debug(`Updating SSH keys for ${user.uid} to ${JSON.stringify(config)}`);

await modifySSHFile(user, config);

logger.info(`Updated SSH keys for ${user.uid} to ${JSON.stringify(config)}`);
};
16 changes: 15 additions & 1 deletion src/integration/localAgent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from 'axios';

import { EmailForwardingConfig } from '../controllers/accountController';
import { EmailForwardingConfig, SSHConfig } from '../controllers/accountController';
import { CreateAccountData } from '../functions/createAccount';

const localAgent = axios.create({
Expand Down Expand Up @@ -39,6 +39,20 @@ export const getForwardFile = async (user: any): Promise<string> => {
return (await localAgent.get(`/forwardFile/${user.classYear}/${user.uid}`)).data;
};

export const modifySSHFile = async (user: any, config: SSHConfig) => {
let SSHString = `${config.keys}\n`;

await localAgent.post(`/SSHFile/${user.classYear}/${user.uid}`, SSHString, {
headers: {
'Content-Type': 'text/plain',
},
});
};

export const getSSHFile = async (user: any): Promise<string> => {
return (await localAgent.get(`/sshFile/${user.classYear}/${user.uid}`)).data;
};

export const whitelistMinecraftUser = async (uuid: string): Promise<void> => {
await localAgent.post(`/mcWhitelist/${uuid}`);
};
Expand Down
18 changes: 17 additions & 1 deletion src/routes/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as jf from 'joiful';

import * as controller from '../controllers/accountController';
import { HttpException } from '../error/httpException';
import { getForwardFile } from '../integration/localAgent';
import { getForwardFile, getSSHFile } from '../integration/localAgent';
import { catchErrors } from '../util/asyncCatch';
import { isLoggedIn } from '../util/authUtils';
import { logger } from '../util/logging';
Expand Down Expand Up @@ -123,6 +123,7 @@ router.get(
catchErrors(async (req: any, res, next) => {
return res.render('account', {
forwardFileText: await getForwardFile(req.user),
sshFileText: await getSSHFile(req.user)
});
}),
);
Expand All @@ -142,4 +143,19 @@ router.post(
}),
);

router.post(
'/configSSH',
isLoggedIn,
catchErrors(async (req: any, res, next) => {
const { error, value } = jf.validateAsClass(req.body, controller.SSHConfig);
if (error) {
throw new HttpException(400, { message: `Invalid request: ${error.message}` });
}

controller.configureSSH(req.user, value);

res.redirect('/account');
}),
);

export const accountRouter = router;
84 changes: 84 additions & 0 deletions views/account.pug
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,72 @@ include include/sauce-common
});
})();
.accordion-item
h2#headingSSH.accordion-header
button.accordion-button.collapsed(
type='button',
data-bs-toggle='collapse',
data-bs-target='#collapseSSH',
aria-expanded='false',
aria-controls='collapseSSH'
)
| Advanced SSH settings
#collapseSSH.accordion-collapse.collapse(aria-labelledby='headingSSH')
.accordion-body
h3 SSH Authorized Keys
button.btn.btn-link.btn-sm.p-0.mb-2(
data-bs-toggle='modal',
data-bs-target='#sshHelpModal'
) What's this?
if sshFileText
p Your authorized_keys file (at #[code #{ user.homeDirectory }/.ssh/authorized_keys]) contains the following:
.card.mb-3(style='width: 100%')
.card-body
pre.mb-0= sshFileText
else
p You currently don't have an authorized_keys file.

hr

h4 Add keys

form#sshForm.container.mb-3.gx-0(
action='/account/configSSH',
method='post',
novalidate
)
input(type='hidden', name='_csrf', value=csrfToken())
.row
.col-auto.pe-0
input#sshKeys.form-control.form-control-sm(
type='text',
aria-label='input for another ssh key',
name='keys'
)
.row
.col-auto.mt-1
//- TODO add a confirmation
button.btn.btn-sm.btn-primary(type='submit') Apply

//- this is separate from the main script because it has to activate after all the form stuff is there
script(type='text/javascript').
(function () {
'use strict';
const form = document.getElementById('sshForm');

form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();

Array.prototype.slice.call(document.querySelectorAll('#sshForm .validate-me')).forEach(function (item) {
item.classList.add('was-validated');
});
}
});
})();

#forwardingHelpModal.modal.fade(
tabindex='-1',
aria-labelledby='forwardingHelpModalTitle',
Expand Down Expand Up @@ -156,6 +222,24 @@ include include/sauce-common
choose to deposit a copy in your local mailbox. For advanced users, you can always
manually edit your .forward file in your home directory on our SSH server, though if you
edit your settings through this page it will overwrite any existing directives.

#sshHelpModal.modal.fade(
tabindex='-1',
aria-labelledby='sshHelpModalTitle',
aria-hidden='true'
)
.modal-dialog
.modal-content
.modal-header
h5#sshHelpModalTitle.modal-title About SSH Keys
button.btn-close(type='button', data-bs-dismiss='modal', aria-label='Close')
.modal-body
p.
Your SCCS account also gives you access to our SSH servers at
#[code robin.sccs.swarthmore.edu]. This service is offered to give students accesss to
more powerful hardware that SCCS can administrate. This page allows you to drop an SSH
key so you don't have to continuously type your passsword in when SSH'ing in.

script(type='text/javascript').
const UID = '#{user.uid}';
script(type='text/javascript', src='/dist/js/account.js')

0 comments on commit d0f4b62

Please sign in to comment.