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
|
#!/usr/bin/env node
const uuid = require('uuid');
const fs = require('fs');
const jwt = require('jsonwebtoken');
const request = require('request-promise-native');
class AMOClient {
constructor(issuer, secret) {
this.issuer = issuer;
this.secret = secret;
}
async getProfile() {
let token = this._getJwtToken();
let response = await request({
url: 'https://addons.mozilla.org/api/v4/accounts/profile/',
method: 'GET',
headers: {
Authorization: 'JWT ' + token,
}
});
return response;
};
async uploadVersion(guid, version, xpiPath) {
let token = this._getJwtToken();
const formData = {
upload: fs.createReadStream(xpiPath),
};
let url = `https://addons.mozilla.org/api/v4/addons/${encodeURIComponent(guid)}/versions/${encodeURIComponent(version)}/`
let response = await request({
url,
formData,
method: 'PUT',
headers: {
Authorization: 'JWT ' + token,
}
});
return response;
}
_getJwtToken() {
// See https://addons-server.readthedocs.io/en/latest/topics/api/auth.html
const issuedAt = Math.floor(Date.now() / 1000);
const payload = {
iss: this.issuer,
jti: uuid.v4(),
iat: issuedAt,
exp: issuedAt + 60,
};
return jwt.sign(payload, this.secret, { algorithm: 'HS256' });
}
}
const run = async() => {
let args = process.argv;
if (args.length != 5) {
console.error(`USAGE: ${args[1]} GUID VERSION XPI_PATH`)
console.error('')
console.error('Environment variables')
console.error(' JWT_ISSUER: JWT issuer generated by AMO')
console.error(' JWT_SECRET: JWT secret token generated by AMO')
process.exit(2);
}
let guid = args[2];
let version = args[3];
let xpiPath = args[4]
let jwtIssuer = process.env['JWT_ISSUER'];
let jwtSecret = process.env['JWT_SECRET'];
if (typeof jwtIssuer === 'undefined' || jwtIssuer.length === 0) {
console.error('JWT_ISSUER not set');
process.exit(2);
}
if (typeof jwtSecret === 'undefined' || jwtSecret.length === 0) {
console.error('JWT_SECRET not set');
process.exit(2);
}
let amo = new AMOClient(jwtIssuer, jwtSecret);
console.log(`Uploading ${xpiPath} to ${guid}/${version}`);
let response = await amo.uploadVersion(guid, version, xpiPath);
console.log(response);
};
run().catch((err) => {
console.error(err.error || err.message);
process.exit(1);
});
|