blob: 0a51ae18a638d6b85f9d4ba6b9771bc4889b71bc [file] [log] [blame]
/// Authorize client with Spicerack and OAuth2.0
import 'dart:async';
import 'dart:io';
import 'dart:convert';
const String SPICERACK_AUTH =
"https://www-googleapis-staging.sandbox.google.com/rpc";
const String separatorFlag = "--separator=";
main(List<String> args) {
int now = new DateTime.now().millisecondsSinceEpoch;
String separator = "&";
// I don't want to import a 3rd party arguments parser for a simple script.
// Allow the caller to switch between '&flag=' and ' --flag='
if (args.length > 0 && args[0].startsWith(separatorFlag) ) {
separator = args[0].substring(separatorFlag.length);
}
String serialNumber;
ProcessResult rslt = Process.runSync("serial", []);
serialNumber = rslt.stdout.trim();
makeSignature(now).then((String signature) {
getAuthCode(serialNumber, signature). then((authResponse) {
Map json = JSON.decode(authResponse)['result'];
var oauthClientId = json['oauthClientId'];
var oauthAddress = json['oauthAddress'];
var oauthClientSecret = json['oauthClientSecret'];
getOAuth2Tokens(json['authorizationCode'], oauthAddress, oauthClientId,
oauthClientSecret).then((tokens) {
Map json = JSON.decode(tokens);
print(
"${separator}clientId=$oauthClientId"
"${separator}clientSecret=$oauthClientSecret"
"${separator}oauth2Url=$oauthAddress"
"${separator}refreshToken=${json['refresh_token']}");
});
});
});
}
/**
* Returns the [now], signed with the local device certificate, and base64
* encoded. See [getAuthCode]. This is equivalent to the following:
* $(date +%s | openssl rsautl -sign -inkey /etc/ssl/private/device.key | openssl base64 -A)
*/
Future<String> makeSignature(int now) {
return Process.start("openssl",
["rsautl", "-sign", "-inkey", "/etc/ssl/private/device.key"])
.then((Process sign) {
sign.stdin.write("$now");
sign.stdin.close();
return Process.start("openssl", ["base64", "-A"])
.then((Process base64) {
sign.stdout.pipe(base64.stdin);
return base64.stdout.transform(new Utf8Decoder()).join()
.then((String encOut) => encOut);
});
});
}
/**
* Connect to Spicerack and request an authcode. Spicerack fetches the client
* certificate from CARS based on the [serial] number and then verifies the
* [signature] is valid.
*/
Future<String> getAuthCode(String serial, String signature) {
var map = {
"method": "spicerack.authcode.fetch",
"apiVersion": "v1",
"params": {
"serialNumber": serial,
"signature": signature,
}
};
String authRequest = JSON.encode(map);
return new HttpClient().postUrl(Uri.parse(SPICERACK_AUTH))
.then((HttpClientRequest request) {
request.headers.contentType = new ContentType("application", "json");
request.write(authRequest);
return request.close();
}).then((HttpClientResponse response) =>
response.transform(new Utf8Decoder()).join());
}
/**
* Connect to the Oath2 service to get access tokens.
*/
Future<String> getOAuth2Tokens(String authCode, String authAddress,
String authClientId, String authClientSecret) {
String tokenRequest = "code=$authCode"
"&client_id=$authClientId"
"&client_secret=$authClientSecret"
"&redirect_uri=oob"
"&grant_type=authorization_code";
return new HttpClient().postUrl(Uri.parse(authAddress))
.then((HttpClientRequest request) {
request.headers.contentType =
new ContentType("application", "x-www-form-urlencoded");
request.write(tokenRequest);
return request.close();
}).then((HttpClientResponse response) =>
response.transform(new Utf8Decoder()).join());
}