mirror of https://github.com/grpc/grpc-dart.git
Fix imports (#199)
This commit is contained in:
parent
91564ff7aa
commit
054ac9de3c
|
@ -1,3 +1,7 @@
|
|||
## 2.0.0+1
|
||||
|
||||
* Fix imports to ensure grpc-web.dart has no accidental transitive dependencies on dart:io.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
* Add initial support for grpc-web.
|
||||
|
|
|
@ -8,6 +8,9 @@ The [Dart](https://www.dart.dev/) implementation of
|
|||
|
||||
See the [Dart gRPC Quickstart](https://grpc.io/docs/quickstart/dart.html).
|
||||
|
||||
[grpc-web](https://github.com/grpc/grpc-web) in a browser context is supported by
|
||||
`package:grpc/grpc-web.dart`.
|
||||
|
||||
# Status
|
||||
|
||||
If you experience issues, or if you have feature requests,
|
||||
|
@ -15,8 +18,8 @@ please [open an issue](https://github.com/dart-lang/grpc-dart/issues).
|
|||
|
||||
# Notes
|
||||
|
||||
This library requires Dart SDK version 2.0 or later.
|
||||
This library requires Dart SDK version 2.2.0 or later.
|
||||
|
||||
It currently supports the the [Flutter](https://flutter.dev/) and
|
||||
[Dart native](https://dart.dev/platforms) platforms. The potential
|
||||
addition of gRPC-Web is tracked in [issue 43](https://github.com/grpc/grpc-dart/issues/43).
|
||||
[Dart native](https://dart.dev/platforms) platforms.
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ dependencies:
|
|||
protobuf: ^0.13.4
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^0.10.0
|
||||
build_web_compilers: '^0.4.1'
|
||||
build_runner: ^1.5.2
|
||||
build_web_compilers: ^2.1.1
|
|
@ -17,10 +17,13 @@ export 'src/auth/auth.dart'
|
|||
show
|
||||
BaseAuthenticator,
|
||||
HttpBasedAuthenticator,
|
||||
ComputeEngineAuthenticator,
|
||||
ServiceAccountAuthenticator,
|
||||
JwtServiceAccountAuthenticator;
|
||||
|
||||
export 'src/auth/auth_io.dart'
|
||||
show
|
||||
ComputeEngineAuthenticator,
|
||||
ServiceAccountAuthenticator;
|
||||
|
||||
export 'src/client/call.dart' show CallOptions, ClientCall, MetadataProvider;
|
||||
export 'src/client/client.dart' show Client;
|
||||
export 'src/client/common.dart' show Response, ResponseStream, ResponseFuture;
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:googleapis_auth/auth_io.dart' as auth;
|
||||
import 'package:googleapis_auth/src/crypto/rsa_sign.dart';
|
||||
import 'package:grpc/src/shared/status.dart';
|
||||
import 'package:googleapis_auth/auth.dart' as auth;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../client/call.dart';
|
||||
import '../shared/status.dart';
|
||||
import 'rsa.dart';
|
||||
|
||||
const _tokenExpirationThreshold = Duration(seconds: 30);
|
||||
|
||||
|
@ -75,32 +75,6 @@ abstract class HttpBasedAuthenticator extends BaseAuthenticator {
|
|||
http.Client client, String uri);
|
||||
}
|
||||
|
||||
class ComputeEngineAuthenticator extends HttpBasedAuthenticator {
|
||||
Future<auth.AccessCredentials> obtainCredentialsWithClient(
|
||||
http.Client client, String uri) =>
|
||||
auth.obtainAccessCredentialsViaMetadataServer(client);
|
||||
}
|
||||
|
||||
class ServiceAccountAuthenticator extends HttpBasedAuthenticator {
|
||||
auth.ServiceAccountCredentials _serviceAccountCredentials;
|
||||
final List<String> _scopes;
|
||||
String _projectId;
|
||||
|
||||
ServiceAccountAuthenticator(String serviceAccountJson, this._scopes) {
|
||||
final serviceAccount = jsonDecode(serviceAccountJson);
|
||||
_serviceAccountCredentials =
|
||||
auth.ServiceAccountCredentials.fromJson(serviceAccount);
|
||||
_projectId = serviceAccount['project_id'];
|
||||
}
|
||||
|
||||
String get projectId => _projectId;
|
||||
|
||||
Future<auth.AccessCredentials> obtainCredentialsWithClient(
|
||||
http.Client client, String uri) =>
|
||||
auth.obtainAccessCredentialsViaServiceAccount(
|
||||
_serviceAccountCredentials, _scopes, client);
|
||||
}
|
||||
|
||||
class JwtServiceAccountAuthenticator extends BaseAuthenticator {
|
||||
auth.ServiceAccountCredentials _serviceAccountCredentials;
|
||||
String _projectId;
|
||||
|
@ -152,7 +126,11 @@ auth.AccessToken _jwtTokenFor(
|
|||
|
||||
final data = '$headerBase64.$claimsBase64';
|
||||
|
||||
final signer = RS256Signer(credentials.privateRSAKey);
|
||||
final key = credentials.privateRSAKey;
|
||||
// We convert to our internal version of RSAPrivateKey. See rsa.dart for more
|
||||
// explanation.
|
||||
final signer = RS256Signer(RSAPrivateKey(
|
||||
key.n, key.e, key.d, key.p, key.q, key.dmp1, key.dmq1, key.coeff));
|
||||
final signature = signer.sign(ascii.encode(data));
|
||||
|
||||
final jwt = '$data.${_base64url(signature)}';
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:googleapis_auth/auth_io.dart' as auth;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'auth.dart';
|
||||
|
||||
class ComputeEngineAuthenticator extends HttpBasedAuthenticator {
|
||||
Future<auth.AccessCredentials> obtainCredentialsWithClient(
|
||||
http.Client client, String uri) =>
|
||||
auth.obtainAccessCredentialsViaMetadataServer(client);
|
||||
}
|
||||
|
||||
class ServiceAccountAuthenticator extends HttpBasedAuthenticator {
|
||||
auth.ServiceAccountCredentials _serviceAccountCredentials;
|
||||
final List<String> _scopes;
|
||||
String _projectId;
|
||||
|
||||
ServiceAccountAuthenticator(String serviceAccountJson, this._scopes) {
|
||||
final serviceAccount = jsonDecode(serviceAccountJson);
|
||||
_serviceAccountCredentials =
|
||||
auth.ServiceAccountCredentials.fromJson(serviceAccount);
|
||||
_projectId = serviceAccount['project_id'];
|
||||
}
|
||||
|
||||
String get projectId => _projectId;
|
||||
|
||||
Future<auth.AccessCredentials> obtainCredentialsWithClient(
|
||||
http.Client client, String uri) =>
|
||||
auth.obtainAccessCredentialsViaServiceAccount(
|
||||
_serviceAccountCredentials, _scopes, client);
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
// Copyright (c) 2019, the gRPC project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This implementation is borrowed from googleapis_auth.
|
||||
// TODO(https://github.com/dart-lang/build/issues/2322): If this is fixed we can
|
||||
// go back to doing a src/ import of this. However that is also not ideal.
|
||||
// TODO(sigurdm): Get rid of this when Dart has enough crypto support.
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
/// Used for signing messages with a private RSA key.
|
||||
///
|
||||
/// The implemented algorithm can be seen in
|
||||
/// RFC 3447, Section 9.2 EMSA-PKCS1-v1_5.
|
||||
class RS256Signer {
|
||||
// NIST sha-256 OID (2 16 840 1 101 3 4 2 1)
|
||||
// See a reference for the encoding here:
|
||||
// http://msdn.microsoft.com/en-us/library/bb540809%28v=vs.85%29.aspx
|
||||
static const _RSA_SHA256_ALGORITHM_IDENTIFIER = const [
|
||||
0x06,
|
||||
0x09,
|
||||
0x60,
|
||||
0x86,
|
||||
0x48,
|
||||
0x01,
|
||||
0x65,
|
||||
0x03,
|
||||
0x04,
|
||||
0x02,
|
||||
0x01
|
||||
];
|
||||
|
||||
final RSAPrivateKey _rsaKey;
|
||||
|
||||
RS256Signer(this._rsaKey);
|
||||
|
||||
List<int> sign(List<int> bytes) {
|
||||
var digest = _digestInfo(sha256.convert(bytes).bytes);
|
||||
var modulusLen = (_rsaKey.bitLength + 7) ~/ 8;
|
||||
|
||||
var block = new Uint8List(modulusLen);
|
||||
var padLength = block.length - digest.length - 3;
|
||||
block[0] = 0x00;
|
||||
block[1] = 0x01;
|
||||
block.fillRange(2, 2 + padLength, 0xFF);
|
||||
block[2 + padLength] = 0x00;
|
||||
block.setRange(2 + padLength + 1, block.length, digest);
|
||||
return RSAAlgorithm.encrypt(_rsaKey, block, modulusLen);
|
||||
}
|
||||
|
||||
static Uint8List _digestInfo(List<int> hash) {
|
||||
// DigestInfo :== SEQUENCE {
|
||||
// digestAlgorithm AlgorithmIdentifier,
|
||||
// digest OCTET STRING
|
||||
// }
|
||||
var offset = 0;
|
||||
var digestInfo = new Uint8List(
|
||||
2 + 2 + _RSA_SHA256_ALGORITHM_IDENTIFIER.length + 2 + 2 + hash.length);
|
||||
{
|
||||
// DigestInfo
|
||||
digestInfo[offset++] = ASN1Parser.SEQUENCE_TAG;
|
||||
digestInfo[offset++] = digestInfo.length - 2;
|
||||
{
|
||||
// AlgorithmIdentifier.
|
||||
digestInfo[offset++] = ASN1Parser.SEQUENCE_TAG;
|
||||
digestInfo[offset++] = _RSA_SHA256_ALGORITHM_IDENTIFIER.length + 2;
|
||||
digestInfo.setAll(offset, _RSA_SHA256_ALGORITHM_IDENTIFIER);
|
||||
offset += _RSA_SHA256_ALGORITHM_IDENTIFIER.length;
|
||||
digestInfo[offset++] = ASN1Parser.NULL_TAG;
|
||||
digestInfo[offset++] = 0;
|
||||
}
|
||||
digestInfo[offset++] = ASN1Parser.OCTET_STRING_TAG;
|
||||
digestInfo[offset++] = hash.length;
|
||||
digestInfo.setAll(offset, hash);
|
||||
}
|
||||
return digestInfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ASN1Parser {
|
||||
static const INTEGER_TAG = 0x02;
|
||||
static const OCTET_STRING_TAG = 0x04;
|
||||
static const NULL_TAG = 0x05;
|
||||
static const OBJECT_ID_TAG = 0x06;
|
||||
static const SEQUENCE_TAG = 0x30;
|
||||
|
||||
static ASN1Object parse(Uint8List bytes) {
|
||||
invalidFormat(String msg) {
|
||||
throw new ArgumentError("Invalid DER encoding: $msg");
|
||||
}
|
||||
|
||||
var data = new ByteData.view(bytes.buffer);
|
||||
int offset = 0;
|
||||
int end = bytes.length;
|
||||
|
||||
checkNBytesAvailable(int n) {
|
||||
if ((offset + n) > end) {
|
||||
invalidFormat('Tried to read more bytes than available.');
|
||||
}
|
||||
}
|
||||
|
||||
List<int> readBytes(int n) {
|
||||
checkNBytesAvailable(n);
|
||||
|
||||
var integerBytes = bytes.sublist(offset, offset + n);
|
||||
offset += n;
|
||||
return integerBytes;
|
||||
}
|
||||
|
||||
int readEncodedLength() {
|
||||
checkNBytesAvailable(1);
|
||||
|
||||
var lengthByte = data.getUint8(offset++);
|
||||
|
||||
// Short length encoding form: This byte is the length itself.
|
||||
if (lengthByte < 0x80) {
|
||||
return lengthByte;
|
||||
}
|
||||
|
||||
// Long length encoding form:
|
||||
// This byte has in bits 0..6 the number of bytes following which encode
|
||||
// the length.
|
||||
int countLengthBytes = lengthByte & 0x7f;
|
||||
checkNBytesAvailable(countLengthBytes);
|
||||
|
||||
int length = 0;
|
||||
while (countLengthBytes > 0) {
|
||||
length = (length << 8) | data.getUint8(offset++);
|
||||
countLengthBytes--;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void readNullBytes() {
|
||||
checkNBytesAvailable(1);
|
||||
var nullByte = data.getUint8(offset++);
|
||||
if (nullByte != 0x00) {
|
||||
invalidFormat('Null byte expect, but was: $nullByte.');
|
||||
}
|
||||
}
|
||||
|
||||
ASN1Object decodeObject() {
|
||||
checkNBytesAvailable(1);
|
||||
var tag = bytes[offset++];
|
||||
switch (tag) {
|
||||
case INTEGER_TAG:
|
||||
int size = readEncodedLength();
|
||||
return new ASN1Integer(RSAAlgorithm.bytes2BigInt(readBytes(size)));
|
||||
case OCTET_STRING_TAG:
|
||||
var size = readEncodedLength();
|
||||
return new ASN1OctetString(readBytes(size));
|
||||
case NULL_TAG:
|
||||
readNullBytes();
|
||||
return new ASN1Null();
|
||||
case OBJECT_ID_TAG:
|
||||
var size = readEncodedLength();
|
||||
return new ASN1ObjectIdentifier(readBytes(size));
|
||||
case SEQUENCE_TAG:
|
||||
var lengthInBytes = readEncodedLength();
|
||||
if ((offset + lengthInBytes) > end) {
|
||||
invalidFormat('Tried to read more bytes than available.');
|
||||
}
|
||||
int endOfSequence = offset + lengthInBytes;
|
||||
|
||||
var objects = <ASN1Object>[];
|
||||
while (offset < endOfSequence) {
|
||||
objects.add(decodeObject());
|
||||
}
|
||||
return new ASN1Sequence(objects);
|
||||
default:
|
||||
invalidFormat(
|
||||
'Unexpected tag $tag at offset ${offset - 1} (end: $end).');
|
||||
}
|
||||
// Unreachable.
|
||||
return null;
|
||||
}
|
||||
|
||||
var obj = decodeObject();
|
||||
if (offset != bytes.length) {
|
||||
throw new ArgumentError('More bytes than expected in ASN1 encoding.');
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ASN1Object {}
|
||||
|
||||
class ASN1Sequence extends ASN1Object {
|
||||
final List<ASN1Object> objects;
|
||||
ASN1Sequence(this.objects);
|
||||
}
|
||||
|
||||
class ASN1Integer extends ASN1Object {
|
||||
final BigInt integer;
|
||||
ASN1Integer(this.integer);
|
||||
}
|
||||
|
||||
class ASN1OctetString extends ASN1Object {
|
||||
final List<int> bytes;
|
||||
ASN1OctetString(this.bytes);
|
||||
}
|
||||
|
||||
class ASN1ObjectIdentifier extends ASN1Object {
|
||||
final List<int> bytes;
|
||||
ASN1ObjectIdentifier(this.bytes);
|
||||
}
|
||||
|
||||
class ASN1Null extends ASN1Object {}
|
||||
|
||||
|
||||
/// Represents integers obtained while creating a Public/Private key pair.
|
||||
class RSAPrivateKey {
|
||||
/// First prime number.
|
||||
final BigInt p;
|
||||
|
||||
/// Second prime number.
|
||||
final BigInt q;
|
||||
|
||||
/// Modulus for public and private keys. Satisfies `n=p*q`.
|
||||
final BigInt n;
|
||||
|
||||
/// Public key exponent. Satisfies `d*e=1 mod phi(n)`.
|
||||
final BigInt e;
|
||||
|
||||
/// Private key exponent. Satisfies `d*e=1 mod phi(n)`.
|
||||
final BigInt d;
|
||||
|
||||
/// Different form of [p]. Satisfies `dmp1=d mod (p-1)`.
|
||||
final BigInt dmp1;
|
||||
|
||||
/// Different form of [p]. Satisfies `dmq1=d mod (q-1)`.
|
||||
final BigInt dmq1;
|
||||
|
||||
/// A coefficient which satisfies `coeff=q^-1 mod p`.
|
||||
final BigInt coeff;
|
||||
|
||||
/// The number of bits used for the modulus. Usually 1024, 2048 or 4096 bits.
|
||||
int get bitLength => n.bitLength;
|
||||
|
||||
RSAPrivateKey(
|
||||
this.n, this.e, this.d, this.p, this.q, this.dmp1, this.dmq1, this.coeff);
|
||||
}
|
||||
|
||||
/// Provides a [encrypt] method for encrypting messages with a [RSAPrivateKey].
|
||||
abstract class RSAAlgorithm {
|
||||
/// Performs the encryption of [bytes] with the private [key].
|
||||
/// Others who have access to the public key will be able to decrypt this
|
||||
/// the result.
|
||||
///
|
||||
/// The [intendedLength] argument specifies the number of bytes in which the
|
||||
/// result should be encoded. Zero bytes will be used for padding.
|
||||
static List<int> encrypt(
|
||||
RSAPrivateKey key, List<int> bytes, int intendedLength) {
|
||||
var message = bytes2BigInt(bytes);
|
||||
var encryptedMessage = _encryptInteger(key, message);
|
||||
return integer2Bytes(encryptedMessage, intendedLength);
|
||||
}
|
||||
|
||||
static BigInt _encryptInteger(RSAPrivateKey key, BigInt x) {
|
||||
// The following is equivalent to `_modPow(x, key.d, key.n) but is much
|
||||
// more efficient. It exploits the fact that we have dmp1/dmq1.
|
||||
var xp = _modPow(x % key.p, key.dmp1, key.p);
|
||||
var xq = _modPow(x % key.q, key.dmq1, key.q);
|
||||
while (xp < xq) {
|
||||
xp += key.p;
|
||||
}
|
||||
return ((((xp - xq) * key.coeff) % key.p) * key.q) + xq;
|
||||
}
|
||||
|
||||
// TODO(kevmoo): see if this can be done more efficiently with BigInt
|
||||
static BigInt _modPow(BigInt b, BigInt e, BigInt m) {
|
||||
if (e < BigInt.one) {
|
||||
return BigInt.one;
|
||||
}
|
||||
if (b < BigInt.zero || b > m) {
|
||||
b = b % m;
|
||||
}
|
||||
var r = BigInt.one;
|
||||
while (e > BigInt.zero) {
|
||||
if ((e & BigInt.one) > BigInt.zero) {
|
||||
r = (r * b) % m;
|
||||
}
|
||||
e >>= 1;
|
||||
b = (b * b) % m;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static BigInt bytes2BigInt(List<int> bytes) {
|
||||
var number = BigInt.zero;
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
number = (number << 8) | new BigInt.from(bytes[i]);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
static List<int> integer2Bytes(BigInt integer, int intendedLength) {
|
||||
if (integer < BigInt.one) {
|
||||
throw new ArgumentError('Only positive integers are supported.');
|
||||
}
|
||||
var bytes = new Uint8List(intendedLength);
|
||||
for (int i = bytes.length - 1; i >= 0; i--) {
|
||||
bytes[i] = (integer & _bigIntFF).toInt();
|
||||
integer >>= 8;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
final _bigIntFF = new BigInt.from(0xff);
|
|
@ -21,7 +21,6 @@ import '../shared/status.dart';
|
|||
import 'common.dart';
|
||||
import 'connection.dart';
|
||||
import 'method.dart';
|
||||
import 'options.dart';
|
||||
import 'transport/transport.dart';
|
||||
|
||||
const _reservedHeaders = [
|
||||
|
|
|
@ -17,7 +17,6 @@ import 'channel.dart';
|
|||
import 'connection.dart';
|
||||
import 'http2_connection.dart' show Http2ClientConnection;
|
||||
import 'options.dart';
|
||||
import 'transport/http2_credentials.dart';
|
||||
|
||||
/// A channel to a virtual gRPC endpoint.
|
||||
///
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import '../../shared/security.dart';
|
||||
import '../options.dart' as options;
|
||||
|
||||
/// Handler for checking certificates that fail validation. If this handler
|
||||
/// returns `true`, the bad certificate is allowed, and the TLS handshake can
|
||||
|
|
|
@ -17,9 +17,9 @@ import 'dart:async';
|
|||
import 'dart:html';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:grpc/src/client/call.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../../client/call.dart';
|
||||
import '../../shared/message.dart';
|
||||
import '../../shared/status.dart';
|
||||
import '../connection.dart';
|
||||
|
|
|
@ -13,11 +13,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'channel.dart';
|
||||
import 'connection.dart';
|
||||
import 'options.dart';
|
||||
import 'transport/xhr_transport.dart';
|
||||
|
||||
/// A channel to a grpc-web endpoint.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
name: grpc
|
||||
description: Dart implementation of gRPC, a high performance, open-source universal RPC framework.
|
||||
|
||||
version: 2.0.0
|
||||
version: 2.0.0+1
|
||||
|
||||
author: Dart Team <misc@dartlang.org>
|
||||
homepage: https://github.com/dart-lang/grpc-dart
|
||||
|
|
|
@ -18,7 +18,6 @@ import 'dart:convert';
|
|||
|
||||
import 'package:grpc/src/client/http2_connection.dart';
|
||||
import 'package:grpc/src/shared/message.dart';
|
||||
import 'package:grpc/src/shared/streams.dart';
|
||||
import 'package:http2/transport.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
|
|
@ -17,12 +17,10 @@ import 'dart:async';
|
|||
|
||||
import 'package:grpc/src/client/http2_connection.dart';
|
||||
import 'package:grpc/src/shared/message.dart';
|
||||
import 'package:grpc/src/shared/streams.dart';
|
||||
import 'package:http2/transport.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:grpc/src/client/transport/http2_transport.dart';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
|
|
Loading…
Reference in New Issue