Skip to content

Commit df9b3d1

Browse files
committed
refactor
1 parent 2a7fa39 commit df9b3d1

File tree

3 files changed

+124
-125
lines changed

3 files changed

+124
-125
lines changed

crx3-info

Lines changed: 10 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,34 @@
11
#!/usr/bin/env node
22
'use strict';
33

4-
let crypto = require('crypto')
5-
let Pbf = require('pbf')
64
let sprintf = require('sprintf-js').sprintf
75
let cmd = require('commander')
8-
let crx3_pb = require('./crx3_pb')
9-
let u = require('./').u
6+
let crx = require('./index')
7+
let u = crx.u
108

119
function main() {
1210
cmd.usage('[options] [public.pem] < file.crx')
1311
.option('--key-rsa <idx>', 'rsa public key', parseInt)
1412
.parse(process.argv)
1513

16-
u.read().then(parse).then( hdr => {
14+
u.read().then(crx.parse).then( hdr => {
1715
if (cmd.keyRsa >= 0) {
1816
let der = hdr.sha256_with_rsa[cmd.keyRsa].public_key
19-
return der2pem(der)
17+
return crx.der2pem(der)
2018
}
2119

22-
if (cmd.args[0]) return u.read(cmd.args[0]).then(pem2der).then( key => {
23-
if (!validate(key, hdr.signed_header_data.crx_id))
24-
process.exitCode = 1
25-
return ''
26-
})
20+
if (cmd.args[0]) return u.read(cmd.args[0]).then(crx.pem2der)
21+
.then( key => {
22+
if (!crx.validate(key, hdr.signed_header_data.crx_id))
23+
process.exitCode = 1
24+
return ''
25+
})
2726

2827
return dump(hdr)
2928

3029
}).then(process.stdout.write.bind(process.stdout)).catch(u.err)
3130
}
3231

33-
function pem2der(buf) {
34-
return crypto.createPublicKey(buf).export({type: 'spki', format: 'der'})
35-
}
36-
37-
function der2pem(buf) {
38-
return crypto.createPublicKey({key: buf, type: 'spki', format: 'der'})
39-
.export({type: 'spki', format: 'pem'})
40-
}
41-
4232
function dump(hdr) {
4333
return [
4434
["id", hdr.signed_header_data.crx_id.toString('hex')], // FIXME
@@ -49,35 +39,4 @@ function dump(hdr) {
4939
].map( v => sprintf('%-20s %s', ...v)).join`\n` + "\n"
5040
}
5141

52-
function parse(buf) {
53-
if ("Cr24" !== buf.slice(0, 4).toString()) throw new Error('not a crx file')
54-
if (3 !== len(buf.slice(4, 8))) throw new Error('not a crx3 file')
55-
let header_size = len(buf.slice(8, 12))
56-
let meta = 4*3
57-
let header = buf.slice(12, header_size + meta)
58-
59-
let crx_file_header = parse_header(header)
60-
return Object.assign({
61-
header_total_len: header.length + meta,
62-
payload_len: buf.length - header.length - meta
63-
}, crx_file_header)
64-
}
65-
66-
function parse_header(buf) {
67-
let pbf = new Pbf(buf)
68-
let hdr = crx3_pb.CrxFileHeader.read(pbf)
69-
70-
pbf = new Pbf(hdr.signed_header_data)
71-
hdr.signed_header_data = crx3_pb.SignedData.read(pbf)
72-
return hdr
73-
}
74-
75-
// the first 128 bits of the sha256 hash of the public key must be == crx id
76-
function validate(public_key, id) {
77-
let a = crypto.createHash('sha256').update(public_key).digest().slice(0, 16)
78-
return a.equals(id)
79-
}
80-
81-
function len(buf) { return buf.readUInt32LE(0) }
82-
8342
main()

crx3-new

Lines changed: 5 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,17 @@
11
#!/usr/bin/env node
22
'use strict';
33

4-
let crypto = require('crypto')
5-
let Pbf = require('pbf')
6-
let crx3_pb = require('./crx3_pb')
7-
let u = require('./').u
4+
let crx = require('./index')
5+
let u = crx.u
86

97
async function main() {
108
if (!process.argv[2]) u.err(`Usage: ${u.progname()} private.pem < file.zip`)
119

12-
let [kp, zipdata] = await Promise.all([keypair(process.argv[2]), u.read()])
10+
let [kp, zip] = await Promise.all([crx.keypair(process.argv[2]), u.read()])
1311
.catch(u.err)
1412

15-
let crx = new CrxFile(kp, zipdata)
16-
process.stdout.write(crx.creat())
17-
}
18-
19-
function keypair(file) {
20-
return u.read(file).then( r => ({
21-
public_der: crypto.createPublicKey(r)
22-
.export({type: 'spki', format: 'der'}),
23-
private: crypto.createPrivateKey(r)
24-
}))
25-
}
26-
27-
class CrxFile {
28-
constructor(keypair, payload) {
29-
this.key = keypair
30-
this.payload = payload
31-
}
32-
33-
id() {
34-
return crypto.createHash('sha256')
35-
.update(this.key.public_der).digest().slice(0, 16)
36-
}
37-
38-
signed_data() {
39-
let pb
40-
return this._signed_data || ( // memoization
41-
pb = new Pbf(),
42-
crx3_pb.SignedData.write({crx_id: this.id()}, pb),
43-
this._signed_data = pb.finish()
44-
)
45-
}
46-
47-
sign() {
48-
let magic_str = "CRX3 SignedData\x00"
49-
return crypto.createSign('sha256')
50-
.update(magic_str)
51-
.update(len(this.signed_data()))
52-
.update(this.signed_data())
53-
.update(this.payload)
54-
.sign(this.key.private)
55-
}
56-
57-
header() {
58-
let pb = new Pbf()
59-
crx3_pb.CrxFileHeader.write({
60-
sha256_with_rsa: [{ // AsymmetricKeyProof
61-
public_key: this.key.public_der,
62-
signature: this.sign()
63-
}],
64-
signed_header_data: this.signed_data()
65-
}, pb)
66-
return pb.finish()
67-
}
68-
69-
creat() {
70-
let magic_str = Buffer.from('Cr24')
71-
let version = len('xxx')
72-
let header_size = len(this.header())
73-
74-
return Buffer.concat([magic_str, version, header_size, this.header(),
75-
this.payload])
76-
}
77-
}
78-
79-
function len(o) { // 4 bytes, little-endian
80-
let buf = Buffer.alloc(4)
81-
buf.writeUInt32LE(o.length, 0)
82-
return buf
13+
let maker = new crx.Maker(kp, zip)
14+
process.stdout.write(maker.creat())
8315
}
8416

8517
main()

index.js

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
'use strict';
22

3+
let crypto = require('crypto')
34
let fs = require('fs')
45
let path = require('path')
56
let log = require('util').debuglog(progname())
7+
let Pbf = require('pbf')
8+
let crx3_pb = require('./crx3_pb')
69

710
function read(file) {
811
let stream = file ? fs.createReadStream(file) : process.stdin
@@ -20,6 +23,111 @@ function err(s) {
2023
process.exit(1)
2124
}
2225

23-
function progname() { return path.basename(process.argv[1]) }
26+
function progname() { return path.basename(process.argv[1] || 'omglol') }
2427

2528
exports.u = { read, err, progname }
29+
30+
exports.parse = function(buf) {
31+
let len = buf => buf.readUInt32LE(0)
32+
33+
if ("Cr24" !== buf.slice(0, 4).toString()) throw new Error('not a crx file')
34+
if (3 !== len(buf.slice(4, 8))) throw new Error('not a crx3 file')
35+
let header_size = len(buf.slice(8, 12))
36+
let meta = 4*3
37+
let header = buf.slice(12, header_size + meta)
38+
39+
let crx_file_header = parse_header(header)
40+
return Object.assign({
41+
header_total_len: header.length + meta,
42+
payload_len: buf.length - header.length - meta
43+
}, crx_file_header)
44+
}
45+
46+
function parse_header(buf) {
47+
let pbf = new Pbf(buf)
48+
let hdr = crx3_pb.CrxFileHeader.read(pbf)
49+
50+
pbf = new Pbf(hdr.signed_header_data)
51+
hdr.signed_header_data = crx3_pb.SignedData.read(pbf)
52+
return hdr
53+
}
54+
55+
// the first 128 bits of the sha256 hash of the public key must be == crx id
56+
exports.validate = function(public_key, id) {
57+
let a = crypto.createHash('sha256').update(public_key).digest().slice(0, 16)
58+
return a.equals(id)
59+
}
60+
61+
exports.pem2der = function(buf) {
62+
return crypto.createPublicKey(buf).export({type: 'spki', format: 'der'})
63+
}
64+
65+
exports.der2pem = function(buf) {
66+
return crypto.createPublicKey({key: buf, type: 'spki', format: 'der'})
67+
.export({type: 'spki', format: 'pem'})
68+
}
69+
70+
exports.keypair = function(file) {
71+
return read(file).then( r => ({
72+
public_der: exports.pem2der(r),
73+
private: crypto.createPrivateKey(r)
74+
}))
75+
}
76+
77+
exports.Maker = class {
78+
constructor(keypair, payload) {
79+
this.key = keypair
80+
this.payload = payload
81+
}
82+
83+
id() {
84+
return crypto.createHash('sha256')
85+
.update(this.key.public_der).digest().slice(0, 16)
86+
}
87+
88+
signed_data() {
89+
let pb
90+
return this._signed_data || ( // memoization
91+
pb = new Pbf(),
92+
crx3_pb.SignedData.write({crx_id: this.id()}, pb),
93+
this._signed_data = pb.finish()
94+
)
95+
}
96+
97+
sign() {
98+
let magic_str = "CRX3 SignedData\x00"
99+
return crypto.createSign('sha256')
100+
.update(magic_str)
101+
.update(len(this.signed_data()))
102+
.update(this.signed_data())
103+
.update(this.payload)
104+
.sign(this.key.private)
105+
}
106+
107+
header() {
108+
let pb = new Pbf()
109+
crx3_pb.CrxFileHeader.write({
110+
sha256_with_rsa: [{ // AsymmetricKeyProof
111+
public_key: this.key.public_der,
112+
signature: this.sign()
113+
}],
114+
signed_header_data: this.signed_data()
115+
}, pb)
116+
return pb.finish()
117+
}
118+
119+
creat() {
120+
let magic_str = Buffer.from('Cr24')
121+
let version = len('xxx')
122+
let header_size = len(this.header())
123+
124+
return Buffer.concat([magic_str, version, header_size, this.header(),
125+
this.payload])
126+
}
127+
}
128+
129+
function len(o) { // 4 bytes, little-endian
130+
let buf = Buffer.alloc(4)
131+
buf.writeUInt32LE(o.length, 0)
132+
return buf
133+
}

0 commit comments

Comments
 (0)