Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
b1f17c9c
Commit
b1f17c9c
authored
Nov 03, 2015
by
Matt Perry
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1923 from mpcomplete/tests.2
Add tests for flx Bundle.
parents
827af771
713d6543
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
115 additions
and
35 deletions
+115
-35
bundle.dart
packages/flx/lib/bundle.dart
+17
-15
signing.dart
packages/flx/lib/signing.dart
+25
-17
bundle_test.dart
packages/unit/test/flx/bundle_test.dart
+70
-0
signing_test.dart
packages/unit/test/flx/signing_test.dart
+3
-3
No files found.
packages/flx/lib/bundle.dart
View file @
b1f17c9c
...
...
@@ -18,6 +18,8 @@ const String kBundleMagic = '#!mojo mojo:sky_viewer\n';
// more flexbile about what we accept.
const
String
kBundleMagicPrefix
=
'#!mojo '
;
typedef
Stream
<
List
<
int
>>
StreamOpener
();
Future
<
List
<
int
>>
_readBytesWithLength
(
RandomAccessFile
file
)
async
{
ByteData
buffer
=
new
ByteData
(
4
);
await
file
.
readInto
(
buffer
.
buffer
.
asUint8List
());
...
...
@@ -39,13 +41,13 @@ Future<String> _readLine(RandomAccessFile file) async {
}
// Writes a 32-bit length followed by the content of [bytes].
void
_writeBytesWithLengthSync
(
File
outputFile
,
List
<
int
>
bytes
)
{
void
_writeBytesWithLengthSync
(
RandomAccess
File
outputFile
,
List
<
int
>
bytes
)
{
if
(
bytes
==
null
)
bytes
=
new
Uint8List
(
0
);
assert
(
bytes
.
length
<
0xffffffff
);
ByteData
length
=
new
ByteData
(
4
)..
setUint32
(
0
,
bytes
.
length
,
Endianness
.
LITTLE_ENDIAN
);
outputFile
.
write
AsBytesSync
(
length
.
buffer
.
asUint8List
(),
mode:
FileMode
.
APPEND
);
outputFile
.
write
AsBytesSync
(
bytes
,
mode:
FileMode
.
APPEND
);
outputFile
.
write
FromSync
(
length
.
buffer
.
asUint8List
()
);
outputFile
.
write
FromSync
(
bytes
);
}
// Represents a parsed .flx Bundle. Contains information from the bundle's
...
...
@@ -70,13 +72,14 @@ class Bundle {
this
.
path
,
this
.
manifest
,
contentBytes
,
KeyPair
keyPair:
null
Asymmetric
KeyPair
keyPair:
null
})
:
_contentBytes
=
contentBytes
{
assert
(
path
!=
null
);
assert
(
manifest
!=
null
);
assert
(
_contentBytes
!=
null
);
manifestBytes
=
serializeManifest
(
manifest
,
keyPair
?.
publicKey
,
_contentBytes
);
signatureBytes
=
signManifest
(
manifestBytes
,
keyPair
?.
privateKey
);
_openContentStream
=
()
=>
new
Stream
.
fromIterable
(<
List
<
int
>>[
_contentBytes
]);
}
final
String
path
;
...
...
@@ -84,9 +87,8 @@ class Bundle {
List
<
int
>
manifestBytes
;
Map
<
String
,
dynamic
>
manifest
;
// File byte offset of the start of the zip content. Only valid when opened
// from a file.
int
_contentOffset
;
// Callback to open a Stream containing the bundle content data.
StreamOpener
_openContentStream
;
// Zip content bytes. Only valid when created in memory.
List
<
int
>
_contentBytes
;
...
...
@@ -100,7 +102,8 @@ class Bundle {
}
signatureBytes
=
await
_readBytesWithLength
(
file
);
manifestBytes
=
await
_readBytesWithLength
(
file
);
_contentOffset
=
await
file
.
position
();
int
contentOffset
=
await
file
.
position
();
_openContentStream
=
()
=>
new
File
(
path
).
openRead
(
contentOffset
);
file
.
close
();
String
manifestString
=
UTF8
.
decode
(
manifestBytes
);
...
...
@@ -115,14 +118,12 @@ class Bundle {
return
bundle
;
}
// When opened from a file, verifies that the package has a valid signature
// and content.
// Verifies that the package has a valid signature and content.
Future
<
bool
>
verifyContent
()
async
{
assert
(
_contentOffset
!=
null
);
if
(!
verifyManifestSignature
(
manifest
,
manifestBytes
,
signatureBytes
))
return
false
;
Stream
<
List
<
int
>>
content
=
await
new
File
(
path
).
openRead
(
_contentOffset
);
Stream
<
List
<
int
>>
content
=
_openContentStream
(
);
BigInteger
expectedHash
=
new
BigInteger
(
manifest
[
'content-hash'
],
10
);
if
(!
await
verifyContentHash
(
expectedHash
,
content
))
return
false
;
...
...
@@ -133,10 +134,11 @@ class Bundle {
// Writes the in-memory representation to disk.
void
writeSync
()
{
assert
(
_contentBytes
!=
null
);
File
outputFile
=
new
File
(
path
);
outputFile
.
write
As
StringSync
(
'#!mojo mojo:sky_viewer
\n
'
);
RandomAccessFile
outputFile
=
new
File
(
path
).
openSync
(
mode:
FileMode
.
WRITE
);
outputFile
.
writeStringSync
(
'#!mojo mojo:sky_viewer
\n
'
);
_writeBytesWithLengthSync
(
outputFile
,
signatureBytes
);
_writeBytesWithLengthSync
(
outputFile
,
manifestBytes
);
outputFile
.
writeAsBytesSync
(
_contentBytes
,
mode:
FileMode
.
APPEND
,
flush:
true
);
outputFile
.
writeFromSync
(
_contentBytes
);
outputFile
.
close
();
}
}
packages/flx/lib/signing.dart
View file @
b1f17c9c
...
...
@@ -12,6 +12,8 @@ import 'package:bignum/bignum.dart';
import
'package:cipher/cipher.dart'
;
import
'package:cipher/impl/client.dart'
;
export
'package:cipher/cipher.dart'
show
AsymmetricKeyPair
;
// The ECDSA algorithm parameters we're using. These match the parameters used
// by the Flutter updater package.
class
CipherParameters
{
...
...
@@ -143,26 +145,32 @@ ECPublicKey _publicKeyFromPrivateKey(ECPrivateKey privateKey) {
return
new
ECPublicKey
(
Q
,
privateKey
.
parameters
);
}
class
KeyPair
{
KeyPair
(
this
.
publicKey
,
this
.
privateKey
);
AsymmetricKeyPair
keyPairFromPrivateKeyFileSync
(
String
privateKeyPath
)
{
File
file
=
new
File
(
privateKeyPath
);
if
(!
file
.
existsSync
())
return
null
;
return
keyPairFromPrivateKeyBytes
(
file
.
readAsBytesSync
());
}
ECPublicKey
publicKey
;
ECPrivateKey
privateKey
;
AsymmetricKeyPair
keyPairFromPrivateKeyBytes
(
List
<
int
>
privateKeyBytes
)
{
ECPrivateKey
privateKey
=
_asn1ParsePrivateKey
(
_params
.
domain
,
new
Uint8List
.
fromList
(
privateKeyBytes
));
if
(
privateKey
==
null
)
return
null
;
static
KeyPair
readFromPrivateKeySync
(
String
privateKeyPath
)
{
File
file
=
new
File
(
privateKeyPath
);
if
(!
file
.
existsSync
())
return
null
;
return
fromPrivateKeyBytes
(
file
.
readAsBytesSync
());
}
ECPublicKey
publicKey
=
_publicKeyFromPrivateKey
(
privateKey
);
return
new
AsymmetricKeyPair
(
publicKey
,
privateKey
);
}
static
KeyPair
fromPrivateKeyBytes
(
List
<
int
>
privateKeyBytes
)
{
ECPrivateKey
privateKey
=
_asn1ParsePrivateKey
(
_params
.
domain
,
new
Uint8List
.
fromList
(
privateKeyBytes
));
if
(
privateKey
==
null
)
return
null
;
// TODO(mpcomplete): remove this class when flutter_tools is updated.
class
KeyPair
extends
AsymmetricKeyPair
{
KeyPair
(
PublicKey
publicKey
,
PrivateKey
privateKey
)
:
super
(
publicKey
,
privateKey
);
ECPublicKey
publicKey
=
_publicKeyFromPrivateKey
(
privateKey
);
return
new
KeyPair
(
publicKey
,
privateKey
);
static
KeyPair
readFromPrivateKeySync
(
String
privateKeyPath
)
{
AsymmetricKeyPair
pair
=
keyPairFromPrivateKeyFileSync
(
privateKeyPath
);
if
(
pair
==
null
)
return
null
;
return
new
KeyPair
(
pair
.
publicKey
,
pair
.
privateKey
);
}
}
packages/unit/test/flx/bundle_test.dart
0 → 100644
View file @
b1f17c9c
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'dart:io'
;
import
'package:flx/signing.dart'
;
import
'package:flx/bundle.dart'
;
import
'package:path/path.dart'
as
path
;
import
'package:test/test.dart'
;
main
()
async
{
// The following constant was generated via the openssl shell commands:
// openssl ecparam -genkey -name prime256v1 -out privatekey.pem
// openssl ec -in privatekey.pem -outform DER | base64
const
String
kPrivateKeyBase64
=
'MHcCAQEEIG4Xt+MgsdP/o89kAHz7EVVLKkN+DUfpaBtZfMyFGbUgoAoGCCqGSM49AwEHoUQDQgAElPtbBVPPqKHYXYAgHaxB2hL6sXeFc99YLijTAuAPe2Nbhywan+v4k+nFm0TJJW/mkV+nH+fyBZ98t4UcFCqkOg=='
;
final
List
<
int
>
kPrivateKeyDER
=
BASE64
.
decode
(
kPrivateKeyBase64
);
// Test manifest.
final
Map
<
String
,
dynamic
>
kManifest
=
<
String
,
dynamic
>{
'name'
:
'test app'
,
'version'
:
'1.0.0'
};
// Simple test byte pattern.
final
Uint8List
kTestBytes
=
new
Uint8List
.
fromList
(<
int
>[
1
,
2
,
3
]);
// Create a temp dir and file for the bundle.
Directory
tempDir
=
await
Directory
.
systemTemp
.
createTempSync
(
'bundle_test'
);
String
bundlePath
=
path
.
join
(
tempDir
.
path
,
'bundle.flx'
);
AsymmetricKeyPair
keyPair
=
keyPairFromPrivateKeyBytes
(
kPrivateKeyDER
);
Map
<
String
,
dynamic
>
manifest
=
JSON
.
decode
(
UTF8
.
decode
(
serializeManifest
(
kManifest
,
keyPair
.
publicKey
,
kTestBytes
)));
test
(
'verifyContent works'
,
()
async
{
Bundle
bundle
=
new
Bundle
.
fromContent
(
path:
bundlePath
,
manifest:
manifest
,
contentBytes:
kTestBytes
,
keyPair:
keyPair
);
bool
verifies
=
await
bundle
.
verifyContent
();
expect
(
verifies
,
equals
(
true
));
});
test
(
'write/read works'
,
()
async
{
Bundle
bundle
=
new
Bundle
.
fromContent
(
path:
bundlePath
,
manifest:
manifest
,
contentBytes:
kTestBytes
,
keyPair:
keyPair
);
bundle
.
writeSync
();
Bundle
diskBundle
=
await
Bundle
.
readHeader
(
bundlePath
);
expect
(
diskBundle
!=
null
,
equals
(
true
));
expect
(
diskBundle
.
manifestBytes
,
equals
(
bundle
.
manifestBytes
));
expect
(
diskBundle
.
signatureBytes
,
equals
(
bundle
.
signatureBytes
));
expect
(
diskBundle
.
manifest
[
'key'
],
equals
(
bundle
.
manifest
[
'key'
]));
expect
(
diskBundle
.
manifest
[
'key'
],
equals
(
manifest
[
'key'
]));
bool
verifies
=
await
diskBundle
.
verifyContent
();
expect
(
verifies
,
equals
(
true
));
});
test
(
'cleanup'
,
()
async
{
tempDir
.
deleteSync
(
recursive:
true
);
});
}
packages/unit/test/flx/signing_test.dart
View file @
b1f17c9c
...
...
@@ -32,7 +32,7 @@ void main() {
final
int
kTestHash
=
0x039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81
;
test
(
'can read openssl key pair'
,
()
{
KeyPair
keyPair
=
KeyPair
.
f
romPrivateKeyBytes
(
kPrivateKeyDER
);
AsymmetricKeyPair
keyPair
=
keyPairF
romPrivateKeyBytes
(
kPrivateKeyDER
);
expect
(
keyPair
!=
null
,
equals
(
true
));
expect
(
keyPair
.
privateKey
.
d
.
intValue
(),
equals
(
kPrivateKeyD
));
expect
(
keyPair
.
publicKey
.
Q
.
x
.
toBigInteger
().
intValue
(),
equals
(
kPublicKeyQx
));
...
...
@@ -40,7 +40,7 @@ void main() {
});
test
(
'serializeManifest adds key and content-hash'
,
()
{
KeyPair
keyPair
=
KeyPair
.
f
romPrivateKeyBytes
(
kPrivateKeyDER
);
AsymmetricKeyPair
keyPair
=
keyPairF
romPrivateKeyBytes
(
kPrivateKeyDER
);
Uint8List
manifestBytes
=
serializeManifest
(
kManifest
,
keyPair
.
publicKey
,
kTestBytes
);
Map
<
String
,
dynamic
>
decodedManifest
=
JSON
.
decode
(
UTF8
.
decode
(
manifestBytes
));
String
expectedKey
=
BASE64
.
encode
(
keyPair
.
publicKey
.
Q
.
getEncoded
());
...
...
@@ -52,7 +52,7 @@ void main() {
});
test
(
'signManifest and verifyManifestSignature work'
,
()
{
KeyPair
keyPair
=
KeyPair
.
f
romPrivateKeyBytes
(
kPrivateKeyDER
);
AsymmetricKeyPair
keyPair
=
keyPairF
romPrivateKeyBytes
(
kPrivateKeyDER
);
Map
<
String
,
dynamic
>
manifest
=
JSON
.
decode
(
UTF8
.
decode
(
serializeManifest
(
kManifest
,
keyPair
.
publicKey
,
kTestBytes
)));
Uint8List
signatureBytes
=
signManifest
(
kTestBytes
,
keyPair
.
privateKey
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment