Source release 19.3.0

This commit is contained in:
John W. Bruce
2024-09-05 07:02:36 +00:00
parent cd8256726f
commit 11c108a8da
122 changed files with 2259 additions and 1082 deletions

View File

@@ -11,6 +11,39 @@
namespace widevine {
namespace {
std::string EscapeJson(const std::string& input) {
std::string result;
for (std::string::const_iterator c = input.begin(); c != input.end(); ++c) {
switch (*c) {
case '\"':
result += "\\\"";
break;
case '\\':
result += "\\\\";
break;
case '\b':
result += "\\b";
break;
case '\f':
result += "\\f";
break;
case '\n':
result += "\\n";
break;
case '\r':
result += "\\r";
break;
case '\t':
result += "\\t";
break;
default:
result += *c;
break;
}
}
return result;
}
std::string StringMapToJson(
const std::map<std::string, std::string>& string_map) {
std::string json = "{";
@@ -72,7 +105,7 @@ Status WidevineFactoryExtractor::GenerateUploadRequest(std::string& request) {
request_map["model"] = PropertiesCE::GetClientInfo().model_name;
request_map["product"] = PropertiesCE::GetClientInfo().product_name;
request_map["build_info"] = PropertiesCE::GetClientInfo().build_info;
request_map["oemcrypto_build_info"] = oemcrypto_build_info;
request_map["oemcrypto_build_info"] = EscapeJson(oemcrypto_build_info);
request_map["bcc"] = wvutil::Base64Encode(bcc);
std::string request_json = StringMapToJson(request_map);

130
factory_upload_tool/ce/wv_upload_tool.py Normal file → Executable file
View File

@@ -12,6 +12,7 @@ input, with one JSON string per line of input.
"""
import argparse
from http import HTTPStatus
import http.server
import json
import os
@@ -25,6 +26,7 @@ from google.oauth2 import service_account
DEFAULT_BASE = 'https://widevine.googleapis.com/v1beta1'
UPLOAD_PATH = '/uniqueDeviceInfo:batchUpload'
BATCH_CHECK_PATH = '/uniqueDeviceInfo:batchCheck'
TOKEN_CACHE_FILE = os.path.join(
os.path.expanduser('~'), '.device_info_uploader.token'
)
@@ -128,15 +130,15 @@ def parse_args():
Returns:
An argparse.Namespace object populated with the arguments.
"""
parser = argparse.ArgumentParser(description='Upload device info')
parser = argparse.ArgumentParser(description='Widevine BCC Batch Upload/Check Tool')
parser.add_argument("--version", action="version", version="20240822") #yyyymmdd
parser.add_argument(
'--json-csr',
nargs='+',
required=True,
help=(
'list of files containing JSON output from'
' rkp_factory_extraction_tool'
),
help='list of files containing JSON output from factory extraction tool',
)
parser.add_argument('--credentials', help='JSON credentials file')
@@ -161,6 +163,30 @@ def parse_args():
action='store_true',
help='exit on error and stop uploading more CSRs',
)
parser.add_argument(
'--dryrun',
action='store_true',
help=(
'Do not upload anything. Instead print out what actions would have'
' been taken if the --dryrun flag had not been specified.'
),
)
parser.add_argument(
'--check',
action='store_true',
required=False,
help='Perform a batch check on the CSRs.',
)
parser.add_argument(
'--verbose',
action='store_true',
required=False,
help='Print request and response details.',
)
return parser.parse_args()
@@ -177,6 +203,7 @@ def parse_json_csrs(filename, batches):
line_count = 0
for line in open(filename):
line_count = line_count + 1
obj = {}
try:
obj = json.loads(line)
except json.JSONDecodeError as e:
@@ -191,13 +218,16 @@ def parse_json_csrs(filename, batches):
'model': obj['model'],
'product': obj['product'],
'build_info': obj['build_info'],
'oemcrypto_build_info': obj['oemcrypto_build_info'],
})
if device_metadata not in batches:
batches[device_metadata] = []
batches[device_metadata].append(bcc)
except KeyError as e:
die(f'Invalid object at {filename}:{line_count}, missing {e}')
if device_metadata not in batches:
batches[device_metadata] = []
batches[device_metadata].append(bcc)
if line_count == 0:
die('Empty BCC file!')
def format_request_body(args, device_metadata, bccs):
@@ -211,6 +241,17 @@ def format_request_body(args, device_metadata, bccs):
return json.dumps(request).encode('utf-8')
def format_check_request_body(args, bccs):
"""Generate a formatted BatchCheck request buffer for the given build and CSRs."""
request = {
'parent': 'orgs/' + args.org_name,
'request_id': uuid.uuid4().hex,
'device_info': bccs,
}
return json.dumps(request).encode('utf-8')
def load_refresh_token():
if not os.path.exists(TOKEN_CACHE_FILE):
return None
@@ -369,16 +410,52 @@ def upload_batch(args, device_metadata, bccs):
device_metadata: The build for which we're uploading CSRs
bccs: a list of BCCs to be uploaded for the given build
"""
print("Uploading {} bcc(s) for build '{}'".format(len(bccs), device_metadata))
print('Uploading {} bcc(s)'.format(len(bccs)))
if args.verbose:
print("Build: '{}'".format(device_metadata))
body = format_request_body(args, device_metadata, bccs)
print(body)
print(args.endpoint + UPLOAD_PATH)
request = urllib.request.Request(args.endpoint + UPLOAD_PATH)
return batch_action_single_attempt(args, UPLOAD_PATH, body)
def check_batch(args, device_metadata, bccs):
"""Batch check all the CSRs.
Args:
args: The parsed command-line arguments
device_metadata: The build for which we're checking CSRs
bccs: a list of BCCs to be checked for the given build
"""
print('Checking {} bcc(s)'.format(len(bccs)))
if args.verbose:
print("Build: '{}'".format(device_metadata))
body = format_check_request_body(args, bccs)
return batch_action_single_attempt(args, BATCH_CHECK_PATH, body)
def batch_action_single_attempt(args, path, body):
"""Batch action (upload or check existence) for all the CSRs in chunks.
Args:
args: The parsed command-line arguments
csrs: a list of CSRs to be uploaded/checked for the given build
path: The endpoint url for the specific action
body: The formatted request body
"""
if args.verbose:
print('Request body:')
print(body)
print('Request target:')
print(args.endpoint + path)
request = urllib.request.Request(args.endpoint + path)
request.add_header('Content-Type', 'application/json')
request.add_header('X-GFE-SSL', 'yes')
request.add_header(
'Authorization', 'Bearer ' + authenticate_and_fetch_token(args)
)
if args.dryrun:
print('dry run: would have reached to ' + request.full_url)
return HTTPStatus.OK
try:
response = urllib.request.urlopen(request, body)
except urllib.error.HTTPError as e:
@@ -388,20 +465,39 @@ def upload_batch(args, device_metadata, bccs):
sys.exit(1)
response_body = response.read().decode('utf-8')
print(response_body)
if args.verbose:
print('Response body:')
print(response_body)
res = json.loads(response_body)
if 'failedDeviceInfo' in res and args.die_on_error:
sys.exit(1)
if 'failedDeviceInfo' in res:
eprint('Failed to upload/check some device info! Response body:')
eprint(response_body)
eprint('Failed: {} bcc(s)'.format(len(res['failedDeviceInfo'])))
if args.die_on_error:
sys.exit(1)
elif 'successDeviceInfo' in res:
print('Success: {} bcc(s)'.format(len(res['successDeviceInfo'])))
else:
eprint('Failed with unexpected response:')
eprint(response_body)
def main():
args = parse_args()
if args.dryrun:
print('Dry run mode enabled. Service APIs will not be called.')
batches = {}
for filename in args.json_csr:
parse_json_csrs(filename, batches)
if len(batches) > 1:
print('WARNING: {} different device metadata'.format(len(batches)))
for device_metadata, bccs in batches.items():
upload_batch(args, device_metadata, bccs)
if args.check:
check_batch(args, device_metadata, bccs)
else:
upload_batch(args, device_metadata, bccs)
if __name__ == '__main__':