|
|
@@ -6,171 +6,233 @@ const prompt = require('prompt-sync')();
|
|
6
|
6
|
const utf8 = require('utf8');
|
|
7
|
7
|
const crypto = require('crypto');
|
|
8
|
8
|
const request = require('request');
|
|
9
|
|
-const stringify = require('json-stable-stringify')
|
|
|
9
|
+const stringify = require('json-stable-stringify');
|
|
|
10
|
+const fs = require('fs');
|
|
10
|
11
|
|
|
11
|
12
|
class Blih {
|
|
12
|
|
- constructor(options) {
|
|
13
|
|
- this.options = options;
|
|
14
|
|
- this._baseUrl = options.baseurl || 'https://blih.epitech.eu/';
|
|
15
|
|
- this._user = options.user || this.get_user();
|
|
16
|
|
- this._token = options.token || this.token_calc();
|
|
17
|
|
- this._verbose = options.verbose || false;
|
|
18
|
|
- this._userAgent = options.useragent || 'blih-' + program.version;
|
|
19
|
|
- }
|
|
20
|
|
-
|
|
21
|
|
- sign_data(data) {
|
|
22
|
|
- const sign = crypto.createHmac('sha512', this._token);
|
|
23
|
|
- return {
|
|
24
|
|
- user: this._user,
|
|
25
|
|
- signature: sign.update(this._user + stringify(data, {space: " "})).digest('hex'),
|
|
26
|
|
- data: data
|
|
27
|
|
- };
|
|
28
|
|
- }
|
|
29
|
|
-
|
|
30
|
|
- request(options) {
|
|
31
|
|
- const signed_data = this.sign_data(options.data);
|
|
32
|
|
- request({
|
|
33
|
|
- url: options.path,
|
|
34
|
|
- baseUrl: this._baseUrl,
|
|
35
|
|
- method: options.method || 'GET',
|
|
36
|
|
- body: JSON.stringify(signed_data),
|
|
37
|
|
- headers: {
|
|
38
|
|
- 'Content-Type': options.contentType || 'application/json',
|
|
39
|
|
- 'User-Agent': this._userAgent
|
|
40
|
|
- }
|
|
41
|
|
- }, function (err, res, body) {
|
|
42
|
|
- if (err)
|
|
43
|
|
- return console.error('request failed:', err);
|
|
44
|
|
- return console.log(body);
|
|
45
|
|
- });
|
|
46
|
|
- }
|
|
47
|
|
-
|
|
48
|
|
- get_user() {
|
|
49
|
|
- return this.options.user || process.env.LOGNAME || process.env.USER ||
|
|
50
|
|
- process.env.LNAME || process.env.USERNAME;
|
|
51
|
|
- }
|
|
52
|
|
-
|
|
53
|
|
- token_calc() {
|
|
54
|
|
- return crypto.createHash('sha512').update(prompt('Password: ', {echo: '*'})).digest('hex');
|
|
55
|
|
- }
|
|
56
|
|
-
|
|
57
|
|
- repo_create(name, type, description) {
|
|
58
|
|
- var data = { name, type: type || 'git' };
|
|
59
|
|
- if (description)
|
|
60
|
|
- data['description'] = description;
|
|
61
|
|
- return this.request({ path: '/repositories', method:'POST', data: data });
|
|
62
|
|
- }
|
|
|
13
|
+ constructor(options) {
|
|
|
14
|
+ this.options = options;
|
|
|
15
|
+ this._baseUrl = options.baseurl || 'https://blih.epitech.eu/';
|
|
|
16
|
+ this._user = options.user || this.get_user();
|
|
|
17
|
+ this._token = options.token || this.token_calc();
|
|
|
18
|
+ this._verbose = options.verbose || false;
|
|
|
19
|
+ this._userAgent = options.useragent || 'blih-' + program.version;
|
|
|
20
|
+ }
|
|
|
21
|
+
|
|
|
22
|
+ sign_data(data) {
|
|
|
23
|
+ const sign = crypto.createHmac('sha512', this._token);
|
|
|
24
|
+ sign.update(this._user);
|
|
|
25
|
+ if (data)
|
|
|
26
|
+ sign.update(stringify(data, {space: " "}));
|
|
|
27
|
+ return {
|
|
|
28
|
+ user: this._user,
|
|
|
29
|
+ signature: sign.digest('hex'),
|
|
|
30
|
+ data: data
|
|
|
31
|
+ };
|
|
|
32
|
+ }
|
|
|
33
|
+
|
|
|
34
|
+ request(options, cb) {
|
|
|
35
|
+ cb = cb || ((res) => { console.log(res.message); });
|
|
|
36
|
+ const signed_data = this.sign_data(options.data);
|
|
|
37
|
+ request({
|
|
|
38
|
+ url: options.path,
|
|
|
39
|
+ baseUrl: this._baseUrl,
|
|
|
40
|
+ method: options.method || 'GET',
|
|
|
41
|
+ body: JSON.stringify(signed_data),
|
|
|
42
|
+ headers: {
|
|
|
43
|
+ 'Content-Type': options.contentType || 'application/json',
|
|
|
44
|
+ 'User-Agent': this._userAgent
|
|
|
45
|
+ }
|
|
|
46
|
+ }, function (err, res, body) {
|
|
|
47
|
+ body = JSON.parse(body);
|
|
|
48
|
+ if (body.error) {
|
|
|
49
|
+ console.error(`HTTP Error ${res.statusCode}\nError message: '${body.error}'`);
|
|
|
50
|
+ process.exit(0);
|
|
|
51
|
+ }
|
|
|
52
|
+ cb(body);
|
|
|
53
|
+ });
|
|
|
54
|
+ }
|
|
|
55
|
+
|
|
|
56
|
+ get_user() {
|
|
|
57
|
+ return this.options.user || process.env.LOGNAME || process.env.USER ||
|
|
|
58
|
+ process.env.LNAME || process.env.USERNAME;
|
|
|
59
|
+ }
|
|
|
60
|
+
|
|
|
61
|
+ token_calc() {
|
|
|
62
|
+ return crypto.createHash('sha512').update(prompt(`${this._user}'s password: `, {echo: '*'}) || process.exit(1)).digest('hex');
|
|
|
63
|
+ }
|
|
63
|
64
|
}
|
|
64
|
65
|
|
|
65
|
|
-class subcommand {
|
|
66
|
|
- constructor(options) {
|
|
67
|
|
- this.options = options;
|
|
68
|
|
- }
|
|
69
|
|
-}
|
|
|
66
|
+class Subcommand {
|
|
|
67
|
+ constructor(options) {
|
|
|
68
|
+ this.options = options;
|
|
|
69
|
+ this.usage_message = '';
|
|
|
70
|
+ }
|
|
70
|
71
|
|
|
71
|
|
-class Repository extends subcommand {
|
|
72
|
|
- create(params) {
|
|
73
|
|
- if (params.length < 1)
|
|
74
|
|
- return this.usage()
|
|
75
|
|
- const blih = new Blih(this.options)
|
|
76
|
|
- blih.repo_create(params[0]);
|
|
77
|
|
- }
|
|
78
|
|
-
|
|
79
|
|
- list() {
|
|
80
|
|
- console.log(process.argv);
|
|
81
|
|
- }
|
|
82
|
|
-
|
|
83
|
|
- info() {
|
|
84
|
|
- console.log(process.argv);
|
|
85
|
|
- }
|
|
86
|
|
-
|
|
87
|
|
- delete() {
|
|
88
|
|
- console.log(process.argv);
|
|
89
|
|
- }
|
|
90
|
|
-
|
|
91
|
|
- setacl() {
|
|
92
|
|
- console.log(process.argv);
|
|
93
|
|
- }
|
|
94
|
|
-
|
|
95
|
|
- getacl() {
|
|
96
|
|
- console.log(process.argv);
|
|
97
|
|
- }
|
|
98
|
|
-
|
|
99
|
|
- usage() {
|
|
100
|
|
- console.log('Usage: ' + process.argv[1] + ' [options] repository command ...')
|
|
101
|
|
- console.log()
|
|
102
|
|
- console.log('Commands :')
|
|
103
|
|
- console.log('\tcreate repo\t\t\t-- Create a repository named "repo"')
|
|
104
|
|
- console.log('\tinfo repo\t\t\t-- Get the repository metadata')
|
|
105
|
|
- console.log('\tgetacl repo\t\t\t-- Get the acls set for the repository')
|
|
106
|
|
- console.log('\tlist\t\t\t\t-- List the repositories created')
|
|
107
|
|
- console.log('\tsetacl repo user [acl]\t\t-- Set (or remove) an acl for "user" on "repo"')
|
|
108
|
|
- console.log('\t\t\t\t\tACL format:')
|
|
109
|
|
- console.log('\t\t\t\t\tr for read')
|
|
110
|
|
- console.log('\t\t\t\t\tw for write')
|
|
111
|
|
- console.log('\t\t\t\t\ta for admin')
|
|
112
|
|
- }
|
|
|
72
|
+ usage() {
|
|
|
73
|
+ console.log(this.usage_message);
|
|
|
74
|
+ }
|
|
113
|
75
|
}
|
|
114
|
76
|
|
|
115
|
|
-class sshkey extends subcommand {
|
|
116
|
|
- list() {
|
|
117
|
|
-
|
|
118
|
|
- }
|
|
119
|
|
-
|
|
120
|
|
- upload() {
|
|
121
|
|
-
|
|
122
|
|
- }
|
|
123
|
|
-
|
|
124
|
|
- delete() {
|
|
125
|
|
-
|
|
126
|
|
- }
|
|
127
|
|
-
|
|
128
|
|
- usage() {
|
|
129
|
|
-
|
|
130
|
|
- }
|
|
|
77
|
+class Repository extends Subcommand {
|
|
|
78
|
+ constructor(options) {
|
|
|
79
|
+ super(options);
|
|
|
80
|
+ this.usage_message =`
|
|
|
81
|
+ Usage: ${process.argv[1]} [options] repository command ...
|
|
|
82
|
+
|
|
|
83
|
+ Commands :
|
|
|
84
|
+ create repo\t\t\t-- Create a repository named "repo"
|
|
|
85
|
+ info repo\t\t\t-- Get the repository metadata
|
|
|
86
|
+ getacl repo\t\t\t-- Get the acls set for the repository
|
|
|
87
|
+ list\t\t\t-- List the repositories created
|
|
|
88
|
+ setacl repo user [acl]\t-- Set (or remove) an acl for "user" on "repo"
|
|
|
89
|
+ \t\t\t\tACL format:
|
|
|
90
|
+ \t\t\t\t\tr for read
|
|
|
91
|
+ \t\t\t\t\tw for write
|
|
|
92
|
+ \t\t\t\t\ta for admin`;
|
|
|
93
|
+ this.usage_message = this.usage_message.substr(3).replace(/\n\t\t/g, '\n');
|
|
|
94
|
+ }
|
|
|
95
|
+
|
|
|
96
|
+ create(params) {
|
|
|
97
|
+ if (params.length < 1)
|
|
|
98
|
+ return this.usage();
|
|
|
99
|
+ const blih = new Blih(this.options);
|
|
|
100
|
+ blih.request({ path: '/repositories', method:'POST', data: {
|
|
|
101
|
+ name: params[0],
|
|
|
102
|
+ type: 'git',
|
|
|
103
|
+ description: ''
|
|
|
104
|
+ }});
|
|
|
105
|
+ }
|
|
|
106
|
+
|
|
|
107
|
+ list() {
|
|
|
108
|
+ const blih = new Blih(this.options);
|
|
|
109
|
+ blih.request({ path: '/repositories' }, (res) => {
|
|
|
110
|
+ if (res.hasOwnProperty("repositories"))
|
|
|
111
|
+ for (let repo in res.repositories)
|
|
|
112
|
+ console.log(repo);
|
|
|
113
|
+ });
|
|
|
114
|
+ }
|
|
|
115
|
+
|
|
|
116
|
+ info(params) {
|
|
|
117
|
+ if (params.length < 1)
|
|
|
118
|
+ return this.usage();
|
|
|
119
|
+ const blih = new Blih(this.options);
|
|
|
120
|
+ blih.request({ path: `/repository/${params[0]}` }, (res) => {
|
|
|
121
|
+ console.log('Repository info :');
|
|
|
122
|
+ console.log(`name : ${params[0]}`);
|
|
|
123
|
+ if (res.hasOwnProperty("message"))
|
|
|
124
|
+ for (let info in res.message)
|
|
|
125
|
+ console.log(`${info} : ${res.message[info]}`);
|
|
|
126
|
+ });
|
|
|
127
|
+ }
|
|
|
128
|
+
|
|
|
129
|
+ delete(params) {
|
|
|
130
|
+ if (params.length < 1)
|
|
|
131
|
+ return this.usage();
|
|
|
132
|
+ const blih = new Blih(this.options);
|
|
|
133
|
+ blih.request({ path: `/repository/${params[0]}`, method:'DELETE' });
|
|
|
134
|
+ }
|
|
|
135
|
+
|
|
|
136
|
+ setacl(params) {
|
|
|
137
|
+ if (params.length < 2)
|
|
|
138
|
+ return this.usage();
|
|
|
139
|
+ const blih = new Blih(this.options);
|
|
|
140
|
+ blih.request({ path: `/repository/${params[0]}/acls`, method:'POST', data: {
|
|
|
141
|
+ user: params[1],
|
|
|
142
|
+ acl: params[2] || ''
|
|
|
143
|
+ }});
|
|
|
144
|
+ }
|
|
|
145
|
+
|
|
|
146
|
+ getacl(params) {
|
|
|
147
|
+ if (params.length < 1)
|
|
|
148
|
+ return this.usage();
|
|
|
149
|
+ const blih = new Blih(this.options);
|
|
|
150
|
+ blih.request({ path: `/repository/${params[0]}/acls` }, (res) => {
|
|
|
151
|
+ for (let info in res)
|
|
|
152
|
+ console.log(`${info}:${res[info]}`);
|
|
|
153
|
+ });
|
|
|
154
|
+ }
|
|
131
|
155
|
}
|
|
132
|
156
|
|
|
|
157
|
+class SSHKey extends Subcommand {
|
|
|
158
|
+ constructor(options) {
|
|
|
159
|
+ super(options);
|
|
|
160
|
+ this.usage_message = `
|
|
|
161
|
+ Usage: ${process.argv[1]} [options] sshkey command ...
|
|
|
162
|
+
|
|
|
163
|
+ Commands :
|
|
|
164
|
+ upload [file]\t\t\t-- Upload a new ssh-key
|
|
|
165
|
+ list\t\t\t\t-- List the ssh-keys
|
|
|
166
|
+ delete [sshkey]\t\t\t-- Delete the sshkey with comment [sshkey]`;
|
|
|
167
|
+ this.usage_message = this.usage_message.substr(3).replace(/\n\t\t/g, '\n');
|
|
|
168
|
+ }
|
|
|
169
|
+
|
|
|
170
|
+ list() {
|
|
|
171
|
+ const blih = new Blih(this.options);
|
|
|
172
|
+ blih.request({ path: '/sshkeys' }, (res) => {
|
|
|
173
|
+ console.log();
|
|
|
174
|
+ for (let info in res)
|
|
|
175
|
+ console.log(`${info}:\n${res[info]}\n`);
|
|
|
176
|
+ });
|
|
|
177
|
+ }
|
|
|
178
|
+
|
|
|
179
|
+ upload(params) {
|
|
|
180
|
+ if (params.length < 1)
|
|
|
181
|
+ return this.usage();
|
|
|
182
|
+ const file = params[0];
|
|
|
183
|
+ const blih = new Blih(this.options);
|
|
|
184
|
+ fs.readFile(file, 'utf8', (err, data) => {
|
|
|
185
|
+ if (err) {
|
|
|
186
|
+ console.error(`Can't open file : ${file}`);
|
|
|
187
|
+ process.exit(1);
|
|
|
188
|
+ }
|
|
|
189
|
+ blih.request({ path: '/sshkeys', method: 'POST', data: { sshkey: data.trim() } });
|
|
|
190
|
+ });
|
|
|
191
|
+ }
|
|
|
192
|
+
|
|
|
193
|
+ delete(params) {
|
|
|
194
|
+ if (params.length < 1)
|
|
|
195
|
+ return this.usage();
|
|
|
196
|
+ const blih = new Blih(this.options);
|
|
|
197
|
+ blih.request({ path: `/sshkey/${params[0]}`, method: 'DELETE' });
|
|
|
198
|
+ }
|
|
|
199
|
+}
|
|
133
|
200
|
|
|
134
|
|
-program
|
|
135
|
|
-.version('1.7')
|
|
136
|
|
-.option('-v, --verbose', 'Enable verbose mode')
|
|
137
|
|
-.option('-u, --user <user>', 'Set user')
|
|
138
|
|
-.option('-b, --baseurl <url>', 'Set baseurl')
|
|
139
|
|
-.option('-t, --token <token>', 'Set token')
|
|
140
|
|
-.option('-U, --useragent <agent>', 'Set useragent');
|
|
141
|
|
-
|
|
142
|
|
-program
|
|
143
|
|
-.command('repository [params...]')
|
|
144
|
|
-.description('Manages repositories')
|
|
145
|
|
-.action(function (params) {
|
|
146
|
|
- const action = params.shift();
|
|
147
|
|
- var repo = new Repository(program);
|
|
148
|
|
- if (typeof repo[action] === 'function')
|
|
149
|
|
- repo[action](params);
|
|
150
|
|
- else
|
|
151
|
|
- repo.usage();
|
|
152
|
|
-});
|
|
153
|
|
-
|
|
154
|
|
-program
|
|
155
|
|
-.command('sshkey')
|
|
156
|
|
-.description('Manages SSH keys')
|
|
157
|
|
-.action(function (params) {
|
|
158
|
|
- const action = params.unshift();
|
|
159
|
|
- var sshkeys= new sshkey(program);
|
|
160
|
|
- if (typeof sshkeys[action] === 'function')
|
|
161
|
|
- sshkeys[action]();
|
|
162
|
|
- else
|
|
163
|
|
- sshkeys.usage();
|
|
164
|
|
-});
|
|
165
|
|
-
|
|
166
|
|
-program
|
|
167
|
|
-.command('whoami')
|
|
168
|
|
-.description('Ask who you are')
|
|
169
|
|
-.action(function() {
|
|
170
|
|
- console.log('whoami');
|
|
171
|
|
-});
|
|
|
201
|
+program.version('1.7')
|
|
|
202
|
+ .option('-v, --verbose', 'Enable verbose mode [ actually no difference ]')
|
|
|
203
|
+ .option('-u, --user <user>', 'Set user')
|
|
|
204
|
+ .option('-b, --baseurl <url>', 'Set baseurl')
|
|
|
205
|
+ .option('-t, --token <token>', 'Set token')
|
|
|
206
|
+ .option('-U, --useragent <agent>', 'Set useragent');
|
|
|
207
|
+
|
|
|
208
|
+program.command('repository [params...]')
|
|
|
209
|
+ .description('Manages repositories')
|
|
|
210
|
+ .action(function (params) {
|
|
|
211
|
+ var action = params.shift();
|
|
|
212
|
+ const repo = new Repository(program);
|
|
|
213
|
+ if (typeof repo[action] !== 'function')
|
|
|
214
|
+ action = 'usage';
|
|
|
215
|
+ repo[action](params);
|
|
|
216
|
+ });
|
|
|
217
|
+
|
|
|
218
|
+program.command('sshkey [params...]')
|
|
|
219
|
+ .description('Manages SSH keys')
|
|
|
220
|
+ .action(function (params) {
|
|
|
221
|
+ var action = params.shift();
|
|
|
222
|
+ const sshkeys = new SSHKey(program);
|
|
|
223
|
+ if (typeof sshkeys[action] !== 'function')
|
|
|
224
|
+ action = 'usage';
|
|
|
225
|
+ sshkeys[action](params);
|
|
|
226
|
+ });
|
|
|
227
|
+
|
|
|
228
|
+program.command('whoami')
|
|
|
229
|
+ .description('Ask who you are')
|
|
|
230
|
+ .action(function() {
|
|
|
231
|
+ const blih = new Blih(program);
|
|
|
232
|
+ blih.request({ path: "/whoami" });
|
|
|
233
|
+ });
|
|
172
|
234
|
|
|
173
|
235
|
program.parse(process.argv);
|
|
174
|
236
|
|
|
175
|
237
|
if (program.args.length === 0)
|
|
176
|
|
- program.help();
|
|
|
238
|
+ program.help();
|