forked from finos/git-proxy
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathusers.ts
More file actions
125 lines (108 loc) · 4.37 KB
/
users.ts
File metadata and controls
125 lines (108 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { OptionalId, Document, ObjectId } from 'mongodb';
import { toClass } from '../helper';
import { User, PublicKeyRecord } from '../types';
import { connect } from './helper';
import _ from 'lodash';
import { DuplicateSSHKeyError } from '../../errors/DatabaseErrors';
const collectionName = 'users';
export const findUser = async function (username: string): Promise<User | null> {
const collection = await connect(collectionName);
const doc = await collection.findOne({ username: { $eq: username.toLowerCase() } });
return doc ? toClass(doc, User.prototype) : null;
};
export const findUserByEmail = async function (email: string): Promise<User | null> {
const collection = await connect(collectionName);
const doc = await collection.findOne({ email: { $eq: email.toLowerCase() } });
return doc ? toClass(doc, User.prototype) : null;
};
export const findUserByOIDC = async function (oidcId: string): Promise<User | null> {
const collection = await connect(collectionName);
const doc = await collection.findOne({ oidcId: { $eq: oidcId } });
return doc ? toClass(doc, User.prototype) : null;
};
export const getUsers = async function (query: any = {}): Promise<User[]> {
if (query.username) {
query.username = query.username.toLowerCase();
}
if (query.email) {
query.email = query.email.toLowerCase();
}
console.log(`Getting users for query = ${JSON.stringify(query)}`);
const collection = await connect(collectionName);
const docs = await collection.find(query).project({ password: 0 }).toArray();
return _.chain(docs)
.map((x) => toClass(x, User.prototype))
.value();
};
export const deleteUser = async function (username: string): Promise<void> {
const collection = await connect(collectionName);
await collection.deleteOne({ username: username.toLowerCase() });
};
export const createUser = async function (user: User): Promise<void> {
user.username = user.username.toLowerCase();
user.email = user.email.toLowerCase();
if (!user.publicKeys) {
user.publicKeys = [];
}
const collection = await connect(collectionName);
await collection.insertOne(user as OptionalId<Document>);
};
export const updateUser = async (user: Partial<User>): Promise<void> => {
if (user.username) {
user.username = user.username.toLowerCase();
}
if (user.email) {
user.email = user.email.toLowerCase();
}
if (!user.publicKeys) {
user.publicKeys = [];
}
const { _id, ...userWithoutId } = user;
const filter = _id ? { _id: new ObjectId(_id) } : { username: user.username };
const options = { upsert: true };
const collection = await connect(collectionName);
await collection.updateOne(filter, { $set: userWithoutId }, options);
};
export const addPublicKey = async (username: string, publicKey: PublicKeyRecord): Promise<void> => {
// Check if this key already exists for any user
const existingUser = await findUserBySSHKey(publicKey.key);
if (existingUser && existingUser.username.toLowerCase() !== username.toLowerCase()) {
throw new DuplicateSSHKeyError(existingUser.username);
}
// Key doesn't exist for other users
const collection = await connect(collectionName);
const user = await collection.findOne({ username: username.toLowerCase() });
if (!user) {
throw new Error('User not found');
}
const keyExists = user.publicKeys?.some(
(k: PublicKeyRecord) =>
k.key === publicKey.key || (k.fingerprint && k.fingerprint === publicKey.fingerprint),
);
if (keyExists) {
throw new Error('SSH key already exists');
}
await collection.updateOne(
{ username: username.toLowerCase() },
{ $push: { publicKeys: publicKey } },
);
};
export const removePublicKey = async (username: string, fingerprint: string): Promise<void> => {
const collection = await connect(collectionName);
await collection.updateOne(
{ username: username.toLowerCase() },
{ $pull: { publicKeys: { fingerprint: fingerprint } } },
);
};
export const findUserBySSHKey = async function (sshKey: string): Promise<User | null> {
const collection = await connect(collectionName);
const doc = await collection.findOne({ 'publicKeys.key': { $eq: sshKey } });
return doc ? toClass(doc, User.prototype) : null;
};
export const getPublicKeys = async (username: string): Promise<PublicKeyRecord[]> => {
const user = await findUser(username);
if (!user) {
throw new Error('User not found');
}
return user.publicKeys || [];
};