-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathandroidmanagement.dart
128 lines (112 loc) · 3.92 KB
/
androidmanagement.dart
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import 'package:googleapis_auth/auth_io.dart';
import 'package:rakuda/rakuda.dart';
import "package:http/http.dart" as http;
import 'dart:io' show File, Platform;
import 'dart:convert' show jsonDecode;
Future<void> saveCredentials(String keyFilename) async {
final serviceAccountJson = await File(keyFilename).readAsString();
final token = await fetchAccessToken(serviceAccountJson);
await Future.wait([
_ServiceAccountCredentialsCache().put(serviceAccountJson).then((_) {
print('credentials are stored in ~/.androidmanagement');
}),
_AccessTokenCache().put(token).then((_) {
print('access token is stored in ~/.androidmanagement');
}),
]);
}
class _ServiceAccountCredentialsCache {
final FileCache _cache;
_ServiceAccountCredentialsCache()
: _cache = FileCache('androidmanagement', 'credentials');
Future<String?> get() => _cache.get();
Future<void> put(String json) => _cache.put(json);
}
class _AccessTokenCache {
final FileCache _cache;
_AccessTokenCache() : _cache = FileCache('androidmanagement', 'access_token');
Future<String?> get() => _cache.get();
Future<void> put(String token) => _cache.put(token);
Future<void> delete() => _cache.delete();
}
Future<String> fetchAccessToken(String serviceAccountJson) async {
final credentials = ServiceAccountCredentials.fromJson(serviceAccountJson);
final httpClient = http.Client();
final accessCredentials = await obtainAccessCredentialsViaServiceAccount(
credentials,
["https://www.googleapis.com/auth/androidmanagement"],
httpClient,
);
httpClient.close();
return accessCredentials.accessToken.data;
}
Future<Response> auth(PerformRequest performRequest, Request request) async {
final keyJson = await _ServiceAccountCredentialsCache().get();
if (keyJson == null) {
throw Exception('configure is required');
}
final cachedAccessToken = await _AccessTokenCache().get();
final accessToken = cachedAccessToken ?? await fetchAccessToken(keyJson);
request.replaceQueryParameter(
(entry) => entry.value.contains('{projectId}'),
(entry) => MapEntry(
entry.key,
entry.value.replaceAll(
'{projectId}',
jsonDecode(keyJson)['project_id'],
)),
);
request.setHeader('Authorization', 'Bearer $accessToken');
var response = await performRequest(request);
if (response.status < 300) {
if (cachedAccessToken == null) {
await _AccessTokenCache().put(accessToken);
}
} else if (response.status == 401) {
if (cachedAccessToken != null) {
_AccessTokenCache().delete();
final accessToken2 = await fetchAccessToken(keyJson);
request.setHeader('Authorization', 'Bearer $accessToken2');
response = await performRequest(request);
if (response.status < 300) {
await _AccessTokenCache().put(accessToken2);
}
}
}
return response;
}
Future<Response> logging(PerformRequest performRequest, Request request) async {
print(
">> ${request.method} ${request.path} ${request.queryParameters.map((e) => "${e.key}=${e.value}").join('&')}");
final response = await performRequest(request);
print(">> HTTP ${response.status}");
final body = response.body;
if (body != null) {
print(body);
}
return response;
}
Future<void> main(List<String> arguments) async {
if (arguments.isNotEmpty && arguments.first == 'configure') {
if (arguments.length != 2) {
throw Exception('configure path/to/service_account.json');
}
await saveCredentials(arguments[1]);
} else {
if (Platform.environment['DEBUGP'] == '1') {
await createJSONClient(
arguments,
baseURL: 'https://androidmanagement.googleapis.com/v1',
interceptors: [logging, auth],
printResponse: false,
);
} else {
await createJSONClient(
arguments,
baseURL: 'https://androidmanagement.googleapis.com/v1',
interceptors: [auth],
printResponse: true,
);
}
}
}