forked from finos/git-proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpushes.ts
More file actions
164 lines (146 loc) · 4.35 KB
/
pushes.ts
File metadata and controls
164 lines (146 loc) · 4.35 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import fs from 'fs';
import _ from 'lodash';
import Datastore from '@seald-io/nedb';
import { Action } from '../../proxy/actions/Action';
import { toClass } from '../helper';
import * as repo from './repo';
import { PushQuery } from '../types';
const COMPACTION_INTERVAL = 1000 * 60 * 60 * 24; // once per day
// these don't get coverage in tests as they have already been run once before the test
/* istanbul ignore if */
if (!fs.existsSync('./.data')) fs.mkdirSync('./.data');
/* istanbul ignore if */
if (!fs.existsSync('./.data/db')) fs.mkdirSync('./.data/db');
const db = new Datastore({ filename: './.data/db/pushes.db', autoload: true });
db.ensureIndex({ fieldName: 'id', unique: true });
db.setAutocompactionInterval(COMPACTION_INTERVAL);
const defaultPushQuery: PushQuery = {
error: false,
blocked: true,
allowPush: false,
authorised: false,
};
export const getPushes = (query: PushQuery) => {
if (!query) query = defaultPushQuery;
return new Promise((resolve, reject) => {
db.find(query, (err: Error, docs: Action[]) => {
// ignore for code coverage as neDB rarely returns errors even for an invalid query
/* istanbul ignore if */
if (err) {
reject(err);
} else {
resolve(
_.chain(docs)
.map((x) => toClass(x, Action.prototype))
.value(),
);
}
});
});
};
export const getPush = async (id: string) => {
return new Promise<Action | null>((resolve, reject) => {
db.findOne({ id: id }, (err, doc) => {
// ignore for code coverage as neDB rarely returns errors even for an invalid query
/* istanbul ignore if */
if (err) {
reject(err);
} else {
if (!doc) {
resolve(null);
} else {
resolve(toClass(doc, Action.prototype));
}
}
});
});
};
export const deletePush = async (id: string) => {
return new Promise<void>((resolve, reject) => {
db.remove({ id }, (err) => {
// ignore for code coverage as neDB rarely returns errors even for an invalid query
/* istanbul ignore if */
if (err) {
reject(err);
} else {
resolve();
}
});
});
};
export const writeAudit = async (action: Action) => {
return new Promise((resolve, reject) => {
const options = { multi: false, upsert: true };
db.update({ id: action.id }, action, options, (err) => {
// ignore for code coverage as neDB rarely returns errors even for an invalid query
/* istanbul ignore if */
if (err) {
reject(err);
} else {
resolve(null);
}
});
});
};
export const authorise = async (id: string, attestation: any) => {
const action = await getPush(id);
if (!action) {
throw new Error(`push ${id} not found`);
}
action.authorised = true;
action.canceled = false;
action.rejected = false;
action.attestation = attestation;
await writeAudit(action);
return { message: `authorised ${id}` };
};
export const reject = async (id: string) => {
const action = await getPush(id);
if (!action) {
throw new Error(`push ${id} not found`);
}
action.authorised = false;
action.canceled = false;
action.rejected = true;
await writeAudit(action);
return { message: `reject ${id}` };
};
export const cancel = async (id: string) => {
const action = await getPush(id);
if (!action) {
throw new Error(`push ${id} not found`);
}
action.authorised = false;
action.canceled = true;
action.rejected = false;
await writeAudit(action);
return { message: `cancel ${id}` };
};
export const canUserCancelPush = async (id: string, user: string) => {
return new Promise<boolean>(async (resolve) => {
const pushDetail = await getPush(id);
if (!pushDetail) {
resolve(false);
return;
}
const repoName = pushDetail.repoName.replace('.git', '');
const isAllowed = await repo.isUserPushAllowed(repoName, user);
if (isAllowed) {
resolve(true);
} else {
resolve(false);
}
});
};
export const canUserApproveRejectPush = async (id: string, user: string) => {
return new Promise<boolean>(async (resolve) => {
const action = await getPush(id);
if (!action) {
resolve(false);
return;
}
const repoName = action.repoName.replace('.git', '');
const isAllowed = await repo.canUserApproveRejectPushRepo(repoName, user);
resolve(isAllowed);
});
};