11import express , { Request , Response } from 'express' ;
2- const router = express . Router ( ) ;
2+ import { utils } from 'ssh2' ;
33
44import * as db from '../../db' ;
55import { toPublicUser } from './publicApi' ;
66
7+ const router = express . Router ( ) ;
8+ const parseKey = utils . parseKey ;
9+
710router . get ( '/' , async ( req : Request , res : Response ) => {
811 console . log ( 'fetching users' ) ;
912 const users = await db . getUsers ( ) ;
@@ -24,30 +27,40 @@ router.get('/:id', async (req: Request, res: Response) => {
2427// Add SSH public key
2528router . post ( '/:username/ssh-keys' , async ( req : Request , res : Response ) => {
2629 if ( ! req . user ) {
27- res . status ( 401 ) . json ( { error : 'Authentication required' } ) ;
30+ res . status ( 401 ) . json ( { error : 'Login required' } ) ;
2831 return ;
2932 }
3033
3134 const { username, admin } = req . user as { username : string ; admin : boolean } ;
3235 const targetUsername = req . params . username . toLowerCase ( ) ;
3336
34- // Only allow users to add keys to their own account, or admins to add to any account
37+ // Admins can add to any account, users can only add to their own
3538 if ( username !== targetUsername && ! admin ) {
3639 res . status ( 403 ) . json ( { error : 'Not authorized to add keys for this user' } ) ;
3740 return ;
3841 }
3942
4043 const { publicKey } = req . body ;
41- if ( ! publicKey ) {
44+ if ( ! publicKey || typeof publicKey !== 'string' ) {
4245 res . status ( 400 ) . json ( { error : 'Public key is required' } ) ;
4346 return ;
4447 }
4548
46- // Strip the comment from the key (everything after the last space)
47- const keyWithoutComment = publicKey . split ( ' ' ) . slice ( 0 , 2 ) . join ( ' ' ) ;
48-
49- console . log ( 'Adding SSH key' , { targetUsername, keyWithoutComment } ) ;
5049 try {
50+ const parsedKey = parseKey ( publicKey . trim ( ) ) ;
51+
52+ if ( parsedKey instanceof Error ) {
53+ res . status ( 400 ) . json ( { error : `Invalid SSH key: ${ parsedKey . message } ` } ) ;
54+ return ;
55+ }
56+
57+ if ( parsedKey . isPrivateKey ( ) ) {
58+ res . status ( 400 ) . json ( { error : 'Invalid SSH key: Must be a public key' } ) ;
59+ return ;
60+ }
61+
62+ const keyWithoutComment = parsedKey . getPublicSSH ( ) . toString ( 'utf8' ) ;
63+ console . log ( 'Adding SSH key' , { targetUsername, keyWithoutComment } ) ;
5164 await db . addPublicKey ( targetUsername , keyWithoutComment ) ;
5265 res . status ( 201 ) . json ( { message : 'SSH key added successfully' } ) ;
5366 } catch ( error ) {
@@ -59,7 +72,7 @@ router.post('/:username/ssh-keys', async (req: Request, res: Response) => {
5972// Remove SSH public key
6073router . delete ( '/:username/ssh-keys' , async ( req : Request , res : Response ) => {
6174 if ( ! req . user ) {
62- res . status ( 401 ) . json ( { error : 'Authentication required' } ) ;
75+ res . status ( 401 ) . json ( { error : 'Login required' } ) ;
6376 return ;
6477 }
6578
0 commit comments