Widevine SDK Release Branch: beta-19.10.1
This commit is contained in:
BIN
centos/tools/bin/published_devices_cli_deploy.jar
Executable file
BIN
centos/tools/bin/published_devices_cli_deploy.jar
Executable file
Binary file not shown.
BIN
centos/tools/bin/published_devices_delta_deploy.jar
Executable file
BIN
centos/tools/bin/published_devices_delta_deploy.jar
Executable file
Binary file not shown.
@@ -0,0 +1,56 @@
|
||||
########################################
|
||||
## Copyright 2019 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
# Published Devices protocol buffer definitions for the
|
||||
# Widevine Published Devices One Platform API service.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library")
|
||||
|
||||
proto_library(
|
||||
name = "published_devices_proto",
|
||||
srcs = ["published_devices.proto"],
|
||||
deps = [
|
||||
":device_security_profiles_proto",
|
||||
"@com_github_googleapis_googleapis//google/api:annotations_proto",
|
||||
"@com_github_googleapis_googleapis//google/api:field_behavior_proto",
|
||||
"@com_google_protobuf//:timestamp_proto",
|
||||
],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "device_security_profiles_proto",
|
||||
srcs = ["device_security_profiles.proto"],
|
||||
deps = [
|
||||
"@com_github_googleapis_googleapis//google/api:field_behavior_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "published_devices_cc_proto",
|
||||
deps = [":published_devices_proto"],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "published_devices_java_proto",
|
||||
deps = [":published_devices_proto"],
|
||||
)
|
||||
|
||||
java_grpc_library(
|
||||
name = "published_devices_grpc",
|
||||
srcs = [":published_devices_proto"],
|
||||
deps = [
|
||||
":published_devices_java_proto",
|
||||
],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "device_security_profiles_java_proto",
|
||||
deps = [":device_security_profiles_proto"],
|
||||
)
|
||||
@@ -0,0 +1,108 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.chrome.widevine.contentpartners.v1beta1;
|
||||
|
||||
import "google/api/field_behavior.proto";
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "DeviceSecurityProfilesProto";
|
||||
option java_package = "com.google.chrome.widevine.contentpartners.v1beta1";
|
||||
|
||||
|
||||
|
||||
|
||||
message DeviceSecurityProfileCriteria {
|
||||
|
||||
string content_provider = 1 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
repeated string content_owners = 2 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
message ListDeviceSecurityProfilesRequest {
|
||||
|
||||
DeviceSecurityProfileCriteria device_security_profile_criteria = 1 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
message SignedDeviceSecurityProfiles {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bytes device_security_profiles = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
|
||||
|
||||
bytes signature = 2 [(google.api.field_behavior) = REQUIRED];
|
||||
|
||||
HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
message ListDeviceSecurityProfilesResponse {
|
||||
|
||||
|
||||
SignedDeviceSecurityProfiles signed_device_security_profiles = 1
|
||||
[(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum HashAlgorithm {
|
||||
|
||||
|
||||
HASH_ALGORITHM_UNSPECIFIED = 0;
|
||||
|
||||
HASH_ALGORITHM_SHA_1 = 1;
|
||||
|
||||
HASH_ALGORITHM_SHA_256 = 2;
|
||||
|
||||
HASH_ALGORITHM_SHA_384 = 3;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2019 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.chrome.widevine.contentpartners.v1beta1;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option csharp_namespace = "Google.Chrome.Widevine.ContentPartners.V1Beta1";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "PublishedDevicesProtos";
|
||||
option java_package = "com.google.chrome.widevine.contentpartners.v1beta1";
|
||||
|
||||
|
||||
option objc_class_prefix = "GCWPD";
|
||||
|
||||
|
||||
|
||||
|
||||
service PublishedDevicesService {
|
||||
|
||||
|
||||
rpc GetPublishedDevices(PublishedDevicesRequest) returns (PublishedDevices) {
|
||||
|
||||
option (google.api.http) = {
|
||||
post: "/v1beta1/publishedDevices:getSignedBatch"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
rpc RetrieveIndividualDeviceRevocationList(
|
||||
RetrieveIndividualDeviceRevocationListRequest)
|
||||
returns (RetrieveIndividualDeviceRevocationListResponse) {
|
||||
|
||||
option (google.api.http) = {
|
||||
post: "/v1beta1/individualDeviceRevocationList:retrieve"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
rpc ListDeviceSecurityProfiles(ListDeviceSecurityProfilesRequest)
|
||||
returns (ListDeviceSecurityProfilesResponse) {
|
||||
|
||||
option (google.api.http) = {
|
||||
get: "/v1beta1/deviceSecurityProfiles:listDeviceSecurityProfiles"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
message SdkClientInformation {
|
||||
|
||||
string sdk_version = 1;
|
||||
|
||||
uint64 sdk_time_seconds = 2;
|
||||
|
||||
bytes service_certificate = 3;
|
||||
|
||||
string provider = 4;
|
||||
}
|
||||
|
||||
|
||||
message PublishedDevicesRequest {
|
||||
|
||||
bytes sdk_client_information = 1;
|
||||
|
||||
|
||||
|
||||
|
||||
bytes signature = 2;
|
||||
|
||||
|
||||
HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DcslSnapshotType dcsl_snapshot_type = 4
|
||||
[(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
google.protobuf.Timestamp last_dcsl_epoch_time = 5
|
||||
[(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool include_impact_analysis = 6 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
message PublishedDevices {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bytes published_devices = 1;
|
||||
|
||||
|
||||
|
||||
bytes signature = 2;
|
||||
|
||||
|
||||
HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
|
||||
DcslSnapshotType dcsl_snapshot_type = 4
|
||||
[(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
message RetrieveIndividualDeviceRevocationListRequest {
|
||||
|
||||
string provider = 1 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
message RetrieveIndividualDeviceRevocationListResponse {
|
||||
|
||||
|
||||
|
||||
|
||||
bytes global_individual_device_revocation_list = 1
|
||||
[(google.api.field_behavior) = REQUIRED];
|
||||
|
||||
|
||||
bytes provider_individual_device_revocation_list = 2
|
||||
[(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
enum DcslSnapshotType {
|
||||
|
||||
DCSL_SNAPSHOT_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
DCSL_ALPHA = 1;
|
||||
|
||||
|
||||
DCSL_BETA = 2;
|
||||
|
||||
|
||||
DCSL_RELEASED = 3;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
########################################
|
||||
## Copyright 2023 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library")
|
||||
|
||||
proto_library(
|
||||
name = "fraud_detection_and_reporting_service_proto",
|
||||
srcs = ["fraud_detection_and_reporting_service.proto"],
|
||||
deps = [
|
||||
"@com_github_googleapis_googleapis//google/api:annotations_proto",
|
||||
"@com_github_googleapis_googleapis//google/api:field_behavior_proto",
|
||||
],
|
||||
)
|
||||
|
||||
java_proto_library(
|
||||
name = "fraud_detection_and_reporting_service_java_proto",
|
||||
deps = [":fraud_detection_and_reporting_service_proto"],
|
||||
)
|
||||
|
||||
java_grpc_library(
|
||||
name = "fraud_detection_and_reporting_grpc",
|
||||
srcs = [":fraud_detection_and_reporting_service_proto"],
|
||||
deps = [":fraud_detection_and_reporting_service_java_proto"],
|
||||
)
|
||||
@@ -0,0 +1,201 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2022 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.chrome.widevine.frauddetection.v1eap1;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "FraudDetectionAndReportingServiceProto";
|
||||
option java_package = "com.google.chrome.widevine.frauddetection.v1eap1";
|
||||
|
||||
|
||||
|
||||
|
||||
service FraudDetectionAndReportingService {
|
||||
|
||||
rpc CalculateFraudLevel(CalculateFraudLevelRequest)
|
||||
returns (CalculateFraudLevelResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1eap1/fraudDetection:calculateFraudLevel"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
rpc ReportFraudLevel(ReportFraudLevelRequest)
|
||||
returns (ReportFraudLevelResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1eap1/fraudReporting:reportFraudLevel"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
message LicenseRequestInfo {
|
||||
|
||||
message RequestMetadata {
|
||||
|
||||
|
||||
string client_ip_address = 1 [
|
||||
(google.api.field_behavior) = OPTIONAL
|
||||
];
|
||||
|
||||
|
||||
string user_agent = 2;
|
||||
|
||||
|
||||
string provider = 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bytes license_request = 1 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bytes clear_client_id = 2 [
|
||||
(google.api.field_behavior) = OPTIONAL
|
||||
];
|
||||
|
||||
|
||||
RequestMetadata request_metadata = 3;
|
||||
}
|
||||
|
||||
|
||||
message FraudLevel {
|
||||
|
||||
|
||||
enum FraudScore {
|
||||
|
||||
FRAUD_SCORE_UNSPECIFIED = 0;
|
||||
|
||||
|
||||
FRAUD_SCORE_NONE = 1;
|
||||
|
||||
|
||||
FRAUD_SCORE_LOW = 2;
|
||||
|
||||
|
||||
FRAUD_SCORE_MEDIUM = 3;
|
||||
|
||||
|
||||
FRAUD_SCORE_HIGH = 4;
|
||||
|
||||
|
||||
FRAUD_SCORE_CRITICAL = 5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum ConfidenceLevel {
|
||||
|
||||
CONFIDENCE_LEVEL_UNSPECIFIED = 0;
|
||||
|
||||
|
||||
CONFIDENCE_LEVEL_NONE = 1;
|
||||
|
||||
|
||||
CONFIDENCE_LEVEL_LOW = 2;
|
||||
|
||||
|
||||
CONFIDENCE_LEVEL_MEDIUM = 3;
|
||||
|
||||
|
||||
CONFIDENCE_LEVEL_HIGH = 4;
|
||||
|
||||
|
||||
CONFIDENCE_LEVEL_VERIFIED = 5;
|
||||
}
|
||||
|
||||
|
||||
FraudScore fraud_score = 1;
|
||||
|
||||
|
||||
ConfidenceLevel confidence_level = 2;
|
||||
}
|
||||
|
||||
|
||||
message CalculateFraudLevelRequest {
|
||||
|
||||
enum Option {
|
||||
|
||||
OPTION_UNSPECIFIED = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
OPTION_NO_RESULTS = 1;
|
||||
|
||||
|
||||
|
||||
OPTION_LOW_LATENCY = 2;
|
||||
|
||||
|
||||
OPTION_HIGH_LATENCY = 3;
|
||||
}
|
||||
|
||||
|
||||
Option request_option = 1 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
|
||||
|
||||
LicenseRequestInfo license_request_info = 2 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
|
||||
|
||||
|
||||
bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
message CalculateFraudLevelResponse {
|
||||
|
||||
FraudLevel fraud_level = 1;
|
||||
|
||||
|
||||
|
||||
LicenseRequestInfo license_request_info = 2;
|
||||
}
|
||||
|
||||
|
||||
message ReportFraudLevelRequest {
|
||||
|
||||
FraudLevel fraud_level = 1 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
|
||||
|
||||
LicenseRequestInfo license_request_info = 2 [
|
||||
(google.api.field_behavior) = REQUIRED
|
||||
];
|
||||
|
||||
|
||||
string reason = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
|
||||
message ReportFraudLevelResponse {
|
||||
|
||||
FraudLevel fraud_level = 1;
|
||||
|
||||
|
||||
|
||||
LicenseRequestInfo license_request_info = 2;
|
||||
}
|
||||
32
centos/tools/src/testing/cts/common/BUILD
Normal file
32
centos/tools/src/testing/cts/common/BUILD
Normal file
@@ -0,0 +1,32 @@
|
||||
########################################
|
||||
## Copyright 2024 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
COMMON_DATA = [
|
||||
"cts_resources/cert_staging_google_com.der",
|
||||
"cts_resources/dev_cert_status_list.dat",
|
||||
"cts_resources/private_key_staging_google_com.der",
|
||||
"cts_resources/dcsl-google.com_blockbuster-1154-5f30025abf26.json",
|
||||
]
|
||||
|
||||
filegroup(
|
||||
name = "cts_resources",
|
||||
srcs = COMMON_DATA,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cts_resource_config",
|
||||
srcs = ["cts_resource_config.cc"],
|
||||
hdrs = ["cts_resource_config.h"],
|
||||
data = COMMON_DATA,
|
||||
deps = [
|
||||
"//base",
|
||||
"//devtools/build/runtime:get_runfiles_dir",
|
||||
],
|
||||
)
|
||||
106
centos/tools/src/testing/cts/common/cts_resource_config.cc
Normal file
106
centos/tools/src/testing/cts/common/cts_resource_config.cc
Normal file
@@ -0,0 +1,106 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "testing/cts/common/cts_resource_config.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "devtools/build/runtime/get_runfiles_dir.h"
|
||||
|
||||
namespace video_widevine {
|
||||
namespace cts_resource_config {
|
||||
|
||||
using devtools_build::GetDataDependencyFilepath;
|
||||
|
||||
std::map<std::string, std::string> SetupDefaultConfigs() {
|
||||
std::map<std::string, std::string> config_values;
|
||||
config_values.insert(std::make_pair("allow_unknown_device", "1"));
|
||||
config_values.insert(std::make_pair("device_certificate_expiration", "0"));
|
||||
config_values.insert(std::make_pair("provider", "widevine_test"));
|
||||
config_values.insert(
|
||||
std::make_pair("provider_iv", "b9c3c175d69b9905e50715d196326acc"));
|
||||
config_values.insert(std::make_pair(
|
||||
"provider_key",
|
||||
"93338e5289145f5f9990d9c9612bcb2bb79e6a684acc6d0ad34bdb7a475621da"));
|
||||
return config_values;
|
||||
}
|
||||
|
||||
std::string GetServiceCertificate() {
|
||||
// use the jts server cert
|
||||
const std::string resource_path =
|
||||
"google3/testing/cts/common/"
|
||||
"cts_resources/"
|
||||
"cert_staging_google_com.der";
|
||||
// update dependency path for borg
|
||||
std::string resource_path_full = GetDataDependencyFilepath(resource_path);
|
||||
std::ifstream input_file(resource_path_full);
|
||||
if (!input_file.is_open()) {
|
||||
std::cerr << "Error opening file!\n";
|
||||
std::cerr << resource_path << "\n";
|
||||
return "";
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << input_file.rdbuf();
|
||||
std::string service_certificate = buffer.str();
|
||||
input_file.close();
|
||||
return service_certificate;
|
||||
}
|
||||
|
||||
std::string GetServiceCertificatePrivateKey() {
|
||||
// use the jts server cert
|
||||
const std::string resource_path =
|
||||
"google3/testing/cts/common/"
|
||||
"cts_resources/"
|
||||
"private_key_staging_google_com.der";
|
||||
// update dependency path for borg
|
||||
std::string resource_path_full = GetDataDependencyFilepath(resource_path);
|
||||
std::ifstream input_file(resource_path_full);
|
||||
if (!input_file.is_open()) {
|
||||
std::cerr << "Error opening file!\n";
|
||||
std::cerr << resource_path << "\n";
|
||||
return "";
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << input_file.rdbuf();
|
||||
std::string service_certificate_private_key = buffer.str();
|
||||
input_file.close();
|
||||
return service_certificate_private_key;
|
||||
}
|
||||
|
||||
std::string GetDCSLRawData() {
|
||||
const std::string dcsl_path =
|
||||
"google3/testing/cts/common/"
|
||||
"cts_resources/"
|
||||
"dev_cert_status_list.dat";
|
||||
// update dependency path for borg
|
||||
std::string dcsl_path_full = GetDataDependencyFilepath(dcsl_path);
|
||||
std::ifstream input_file(dcsl_path_full);
|
||||
if (!input_file.is_open()) {
|
||||
std::cerr << "Error opening file!\n";
|
||||
std::cerr << dcsl_path << "\n";
|
||||
return "";
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << input_file.rdbuf();
|
||||
std::string dcsl_str = buffer.str();
|
||||
input_file.close();
|
||||
return dcsl_str;
|
||||
}
|
||||
|
||||
std::string GetPrivateKeyPassphrase() {
|
||||
return "mViUNMa3Lag7KJyEl5aphWn4/dkOOI3H/"
|
||||
"D8LSJ0g3t8GLj3lOHGTTjn1Y2XKPqU7M3NlxAw5mFZl";
|
||||
}
|
||||
|
||||
} // namespace cts_resource_config
|
||||
} // namespace video_widevine
|
||||
26
centos/tools/src/testing/cts/common/cts_resource_config.h
Normal file
26
centos/tools/src/testing/cts/common/cts_resource_config.h
Normal file
@@ -0,0 +1,26 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_TESTING_CTS_COMMON_CTS_RESOURCE_CONFIG_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_TESTING_CTS_COMMON_CTS_RESOURCE_CONFIG_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace video_widevine {
|
||||
namespace cts_resource_config {
|
||||
|
||||
std::map<std::string, std::string> SetupDefaultConfigs();
|
||||
std::string GetDCSLRawData();
|
||||
std::string GetServiceCertificate();
|
||||
std::string GetServiceCertificatePrivateKey();
|
||||
std::string GetPrivateKeyPassphrase();
|
||||
} // namespace cts_resource_config
|
||||
} // namespace video_widevine
|
||||
|
||||
#endif // VIDEO_WIDEVINE_EXPORT_TESTING_CTS_COMMON_CTS_RESOURCE_CONFIG_H_
|
||||
22
centos/tools/src/testing/cts/env/BUILD
vendored
Normal file
22
centos/tools/src/testing/cts/env/BUILD
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
########################################
|
||||
## Copyright 2024 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cc_library(
|
||||
name = "wvpl_env",
|
||||
hdrs = ["wvpl_env.h"],
|
||||
deps = [
|
||||
"@abseil_repo//absl/log",
|
||||
"@abseil_repo//absl/strings",
|
||||
"//sdk/external/cpp/wvpl/common:wvpl_types",
|
||||
"//sdk/external/cpp/wvpl/license_server_sdk:wvpl_environment",
|
||||
"//testing/cts/common:cts_resource_config",
|
||||
"//testing/cts/published_devices:published_devices_provider",
|
||||
],
|
||||
)
|
||||
116
centos/tools/src/testing/cts/env/wvpl_env.h
vendored
Normal file
116
centos/tools/src/testing/cts/env/wvpl_env.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_TESTING_CTS_ENV_WVPL_ENV_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_TESTING_CTS_ENV_WVPL_ENV_H_
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_types.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_environment.h"
|
||||
#include "testing/cts/common/cts_resource_config.h"
|
||||
#include "testing/cts/published_devices/published_devices_provider.h"
|
||||
|
||||
namespace video_widevine {
|
||||
namespace cts {
|
||||
namespace wvpl_env {
|
||||
|
||||
using video_widevine::published_devices_provider::GetDCSL;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLEnvironment;
|
||||
|
||||
// Singleton class to get an instance of WvPLEnvironment from wvpl_environment.h
|
||||
class WvplEnv {
|
||||
public:
|
||||
// Gets the instance of WvplEnv singleton which stores a WvPLEnvironment.
|
||||
static WvplEnv* GetInstance() {
|
||||
static WvplEnv* s = new WvplEnv();
|
||||
return s;
|
||||
}
|
||||
// Gets the WvPLEnvironment instance stored inside this singleton.
|
||||
WvPLEnvironment* get_env() { return &wvpl_env_instance_; }
|
||||
// Returns true if env initialization failed for any reason.
|
||||
bool env_setup_failed() { return env_init_failed_; }
|
||||
|
||||
private:
|
||||
WvplEnv()
|
||||
: wvpl_env_instance_(
|
||||
video_widevine::cts_resource_config::SetupDefaultConfigs()) {
|
||||
env_init_failed_ = false;
|
||||
video_widevine_server::wv_pl_sdk::WvPLStatus status =
|
||||
wvpl_env_instance_.Initialize();
|
||||
if (status.ok()) {
|
||||
} else {
|
||||
env_init_failed_ = true;
|
||||
return;
|
||||
}
|
||||
std::string service_cert =
|
||||
video_widevine::cts_resource_config::GetServiceCertificate();
|
||||
std::string service_cert_private_key =
|
||||
video_widevine::cts_resource_config::GetServiceCertificatePrivateKey();
|
||||
|
||||
status = wvpl_env_instance_.SetDrmServiceCertificate(
|
||||
service_cert, service_cert_private_key,
|
||||
video_widevine::cts_resource_config::GetPrivateKeyPassphrase());
|
||||
if (status.ok()) {
|
||||
} else {
|
||||
env_init_failed_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string use_dcsl_from_file = "";
|
||||
if (getenv("USE_DCSL_FROM_FILE") != nullptr) {
|
||||
use_dcsl_from_file = getenv("USE_DCSL_FROM_FILE");
|
||||
}
|
||||
if (use_dcsl_from_file == "True") {
|
||||
std::string dcsl_str_encoded =
|
||||
video_widevine::cts_resource_config::GetDCSLRawData();
|
||||
std::string dcsl_decoded;
|
||||
bool result =
|
||||
absl::WebSafeBase64Unescape(dcsl_str_encoded, &dcsl_decoded);
|
||||
if (!result) {
|
||||
}
|
||||
status = wvpl_env_instance_.SetDeviceCertificateStatusList(dcsl_decoded);
|
||||
if (status.ok()) {
|
||||
} else {
|
||||
env_init_failed_ = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Fetch the device certificate status list.
|
||||
absl::StatusOr<std::string> dcslStatus = GetDCSL(wvpl_env_instance_);
|
||||
if (dcslStatus.ok()) {
|
||||
} else {
|
||||
env_init_failed_ = true;
|
||||
return;
|
||||
}
|
||||
status =
|
||||
wvpl_env_instance_.SetDeviceCertificateStatusList(dcslStatus.value());
|
||||
if (status.ok()) {
|
||||
} else {
|
||||
env_init_failed_ = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WvplEnv() = default;
|
||||
|
||||
WvplEnv(const WvplEnv&) = delete;
|
||||
WvplEnv& operator=(const WvplEnv&) = delete;
|
||||
|
||||
WvPLEnvironment wvpl_env_instance_;
|
||||
bool env_init_failed_;
|
||||
};
|
||||
} // namespace wvpl_env
|
||||
} // namespace cts
|
||||
} // namespace video_widevine
|
||||
|
||||
#endif // VIDEO_WIDEVINE_EXPORT_TESTING_CTS_ENV_WVPL_ENV_H_
|
||||
38
centos/tools/src/testing/cts/published_devices/BUILD
Normal file
38
centos/tools/src/testing/cts/published_devices/BUILD
Normal file
@@ -0,0 +1,38 @@
|
||||
########################################
|
||||
## Copyright 2024 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cc_library(
|
||||
name = "published_devices_provider",
|
||||
srcs = ["published_devices_provider.cc"],
|
||||
hdrs = ["published_devices_provider.h"],
|
||||
deps = [
|
||||
"//base",
|
||||
"//chubby/lib/public:lockservice",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_cc_grpc",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_cc_proto",
|
||||
"//net/eventmanager",
|
||||
"//net/grpc:grpc++",
|
||||
"//net/http:httpserverrequest",
|
||||
"//net/http2/server/lib/public:server",
|
||||
"//net/rpc",
|
||||
|
||||
"@abseil_repo//absl/functional:bind_front",
|
||||
"@abseil_repo//absl/log",
|
||||
"@abseil_repo//absl/log:check",
|
||||
"@abseil_repo//absl/status",
|
||||
"@abseil_repo//absl/status:statusor",
|
||||
"//third_party/grpc",
|
||||
"//third_party/grpc:grpc++",
|
||||
"//thread",
|
||||
"//util:error_space",
|
||||
"//sdk/external/cpp/wvpl/common:wvpl_types",
|
||||
"//sdk/external/cpp/wvpl/license_server_sdk:wvpl_environment",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,94 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "testing/cts/published_devices/published_devices_provider.h"
|
||||
|
||||
#include <wrapper_internal_exception_macros.h>
|
||||
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "google/chrome/widevine/contentpartners/v1beta1/published_devices.grpc.pb.h"
|
||||
#include "google/chrome/widevine/contentpartners/v1beta1/published_devices.pb.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "third_party/grpc/include/grpcpp/channel.h"
|
||||
#include "third_party/grpc/include/grpcpp/client_context.h"
|
||||
#include "third_party/grpc/include/grpcpp/create_channel.h"
|
||||
#include "third_party/grpc/include/grpcpp/security/credentials.h"
|
||||
#include "third_party/grpc/include/grpcpp/support/status.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_types.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_environment.h"
|
||||
|
||||
namespace video_widevine {
|
||||
namespace published_devices_provider {
|
||||
|
||||
using google::chrome::widevine::contentpartners::v1beta1::PublishedDevices;
|
||||
using google::chrome::widevine::contentpartners::v1beta1::
|
||||
PublishedDevicesRequest;
|
||||
using google::chrome::widevine::contentpartners::v1beta1::
|
||||
PublishedDevicesService;
|
||||
|
||||
using video_widevine_server::wv_pl_sdk::WvPLEnvironment;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
|
||||
const char apiServicePath[] = "widevine.googleapis.com";
|
||||
|
||||
absl::StatusOr<PublishedDevices> GetPublishedDevices(
|
||||
const WvPLEnvironment& env) {
|
||||
std::shared_ptr<grpc::Channel> channel = nullptr;
|
||||
PublishedDevices devicesResponse;
|
||||
try {
|
||||
// Create grpc channel.
|
||||
std::shared_ptr<grpc::Channel> channel =
|
||||
grpc::CreateChannel(apiServicePath, grpc::GoogleDefaultCredentials());
|
||||
|
||||
// Create a stub.
|
||||
std::unique_ptr<PublishedDevicesService::Stub> stub(
|
||||
(PublishedDevicesService::NewStub(channel)));
|
||||
PublishedDevicesRequest publishedDevicesRequest;
|
||||
std::string publishedDevicesRequestString;
|
||||
WvPLStatus status =
|
||||
env.GenerateDeviceStatusListRequest(&publishedDevicesRequestString);
|
||||
if (!status.ok()) {
|
||||
return absl::FailedPreconditionError("unable to generate dcsl request: " +
|
||||
status.error_message());
|
||||
}
|
||||
if (!publishedDevicesRequest.ParseFromString(
|
||||
publishedDevicesRequestString)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"unable to parse published devices request");
|
||||
}
|
||||
|
||||
// Send gRPC request.
|
||||
grpc::ClientContext context;
|
||||
grpc::Status grpcStatus = stub->GetPublishedDevices(
|
||||
&context, publishedDevicesRequest, &devicesResponse);
|
||||
if (grpcStatus.ok()) {
|
||||
} else {
|
||||
return absl::FailedPreconditionError("grpc getPublishedDevices failed: " +
|
||||
grpcStatus.error_message());
|
||||
}
|
||||
} catch (const std::exception& exc) {
|
||||
return absl::FailedPreconditionError("failed to retrieve signd list");
|
||||
}
|
||||
return devicesResponse;
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> GetDCSL(const WvPLEnvironment& env) {
|
||||
absl::StatusOr<PublishedDevices> pdResponse = GetPublishedDevices(env);
|
||||
if (!pdResponse.ok()) {
|
||||
return pdResponse.status();
|
||||
}
|
||||
return pdResponse.value().SerializeAsString();
|
||||
}
|
||||
|
||||
} // namespace published_devices_provider
|
||||
} // namespace video_widevine
|
||||
@@ -0,0 +1,32 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_TESTING_CTS_PUBLISHED_DEVICES_PUBLISHED_DEVICES_PROVIDER_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_TESTING_CTS_PUBLISHED_DEVICES_PUBLISHED_DEVICES_PROVIDER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "google/chrome/widevine/contentpartners/v1beta1/published_devices.pb.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_environment.h"
|
||||
|
||||
namespace video_widevine {
|
||||
namespace published_devices_provider {
|
||||
|
||||
absl::StatusOr<
|
||||
google::chrome::widevine::contentpartners::v1beta1::PublishedDevices>
|
||||
GetPublishedDevices(
|
||||
const video_widevine_server::wv_pl_sdk::WvPLEnvironment& env);
|
||||
|
||||
absl::StatusOr<std::string> GetDCSL(
|
||||
const video_widevine_server::wv_pl_sdk::WvPLEnvironment& env);
|
||||
|
||||
} // namespace published_devices_provider
|
||||
} // namespace video_widevine
|
||||
|
||||
#endif // VIDEO_WIDEVINE_EXPORT_TESTING_CTS_PUBLISHED_DEVICES_PUBLISHED_DEVICES_PROVIDER_H_
|
||||
28
centos/tools/src/testing/cts/sdk/BUILD
Normal file
28
centos/tools/src/testing/cts/sdk/BUILD
Normal file
@@ -0,0 +1,28 @@
|
||||
########################################
|
||||
## Copyright 2024 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cc_library(
|
||||
name = "wvpl_sdk",
|
||||
srcs = ["wvpl_sdk.cc"],
|
||||
hdrs = ["wvpl_sdk.h"],
|
||||
deps = [
|
||||
"//google/chrome/widevine/licensedata/v1:content_key_spec_cc_proto",
|
||||
"@abseil_repo//absl/log",
|
||||
"@abseil_repo//absl/status",
|
||||
"@abseil_repo//absl/status:statusor",
|
||||
"//sdk/external/cpp/wvpl/common:wvpl_types",
|
||||
"//sdk/external/cpp/wvpl/license_server_sdk:wvpl_environment",
|
||||
"//sdk/external/cpp/wvpl/license_server_sdk:wvpl_session",
|
||||
"//testing/cts/env:wvpl_env",
|
||||
"//protos/public:license_protocol_cc_proto",
|
||||
"//protos/public:license_protos_cc_proto",
|
||||
"//protos/public:license_services_cc_proto",
|
||||
],
|
||||
)
|
||||
153
centos/tools/src/testing/cts/sdk/wvpl_sdk.cc
Normal file
153
centos/tools/src/testing/cts/sdk/wvpl_sdk.cc
Normal file
@@ -0,0 +1,153 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "testing/cts/sdk/wvpl_sdk.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "google/chrome/widevine/licensedata/v1/content_key_spec.pb.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "sdk/external/cpp/wvpl/common/wvpl_types.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_environment.h"
|
||||
#include "sdk/external/cpp/wvpl/license_server_sdk/wvpl_session.h"
|
||||
#include "testing/cts/env/wvpl_env.h"
|
||||
#include "protos/public/license_protocol.pb.h"
|
||||
#include "protos/public/license_protos.pb.h"
|
||||
#include "protos/public/license_services.pb.h"
|
||||
|
||||
namespace video_widevine {
|
||||
namespace wvpl_sdk {
|
||||
|
||||
using video_widevine_server::wv_pl_sdk::WvPLEnvironment;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLKey;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLPlaybackPolicy;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLRequestType;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLSession;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLStatus;
|
||||
using video_widevine_server::wv_pl_sdk::WvPLWidevinePsshData;
|
||||
|
||||
video_widevine_server::wv_pl_sdk::TrackType get_track_type(
|
||||
std::string track_type) {
|
||||
if (track_type == "SD") {
|
||||
return video_widevine_server::wv_pl_sdk::VIDEO_SD;
|
||||
} else if (track_type == "HD") {
|
||||
return video_widevine_server::wv_pl_sdk::VIDEO_HD;
|
||||
} else if (track_type == "UHD1") {
|
||||
return video_widevine_server::wv_pl_sdk::VIDEO_UHD1;
|
||||
} else if (track_type == "UHD2") {
|
||||
return video_widevine_server::wv_pl_sdk::VIDEO_UHD2;
|
||||
} else if (track_type == "AUDIO") {
|
||||
return video_widevine_server::wv_pl_sdk::AUDIO;
|
||||
} else {
|
||||
return video_widevine_server::wv_pl_sdk::TRACK_TYPE_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
bool add_keys_to_session(WvPLSession& session, std::vector<WvPLKey> wvpl_keys) {
|
||||
for (const WvPLKey& wvpl_key : wvpl_keys) {
|
||||
WvPLStatus status = session.AddKey(wvpl_key);
|
||||
if (!status.ok()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<WvPLKey> create_wvpl_keys_from_content_key_specs(
|
||||
ModularDrmLicenseRequest drmRequest, WvPLWidevinePsshData _wv_pssh_data,
|
||||
bool is_external_license_request) {
|
||||
std::vector<WvPLKey> wvpl_keys;
|
||||
|
||||
for (int i = 0; i < drmRequest.content_key_specs_size(); i++) {
|
||||
WvPLKey wvpl_key;
|
||||
const auto& content_key_spec = drmRequest.content_key_specs(i);
|
||||
wvpl_key.set_key_id(content_key_spec.key_id());
|
||||
wvpl_key.set_key_bytes(content_key_spec.key());
|
||||
wvpl_key.set_key_type(
|
||||
static_cast<video_widevine_server::wv_pl_sdk::KeyType>(
|
||||
content_key_spec.key_type()));
|
||||
wvpl_key.set_track_type(get_track_type(content_key_spec.track_type()));
|
||||
wvpl_keys.push_back(wvpl_key);
|
||||
}
|
||||
return wvpl_keys;
|
||||
}
|
||||
|
||||
// TODO: b/323916039 - Setup handler for /drmRequest
|
||||
absl::StatusOr<std::string> HandleDrmLicenseRequest(std::string requestString) {
|
||||
ModularDrmLicenseRequest drmRequest;
|
||||
if (!drmRequest.ParseFromString(requestString)) {
|
||||
return "";
|
||||
}
|
||||
std::string license_request_payload = drmRequest.payload();
|
||||
std::string response = "";
|
||||
WvPLSession* session;
|
||||
auto wvpl_env_instance =
|
||||
video_widevine::cts::wvpl_env::WvplEnv::GetInstance();
|
||||
WvPLEnvironment* wvpl_env = wvpl_env_instance->get_env();
|
||||
WvPLStatus status =
|
||||
wvpl_env->CreateSession(license_request_payload, &session);
|
||||
if (!status.ok()) {
|
||||
return absl::InternalError("Failed to create session: " +
|
||||
status.error_message());
|
||||
} else {
|
||||
}
|
||||
WvPLRequestType request_type = session->GetRequestType();
|
||||
video_widevine::LicenseRequest license_request = session->request();
|
||||
video_widevine::LicenseRequest::RequestType license_request_type =
|
||||
license_request.type();
|
||||
video_widevine_server::wv_pl_sdk::MessageType message_type =
|
||||
request_type.message_type();
|
||||
bool should_add_keys = false;
|
||||
bool external_license_request = false;
|
||||
switch (message_type) {
|
||||
case SignedMessage::LICENSE_REQUEST:
|
||||
if (license_request_type == video_widevine::LicenseRequest::NEW) {
|
||||
should_add_keys = true;
|
||||
}
|
||||
break;
|
||||
case SignedMessage::EXTERNAL_LICENSE_REQUEST:
|
||||
should_add_keys = true;
|
||||
external_license_request = true;
|
||||
break;
|
||||
case video_widevine_server::wv_pl_sdk::UNKNOWN:
|
||||
case video_widevine_server::wv_pl_sdk::SERVICE_CERTIFICATE_REQUEST:
|
||||
break;
|
||||
}
|
||||
WvPLWidevinePsshData wv_pssh_data;
|
||||
status = session->GetPsshData(&wv_pssh_data);
|
||||
if (!status.ok()) {
|
||||
return absl::InternalError("Failed to get pssh data: " +
|
||||
status.error_message());
|
||||
}
|
||||
|
||||
if (should_add_keys) {
|
||||
std::vector<WvPLKey> wvpl_keys = create_wvpl_keys_from_content_key_specs(
|
||||
drmRequest, wv_pssh_data, external_license_request);
|
||||
bool keys_added = add_keys_to_session(*session, wvpl_keys);
|
||||
if (!keys_added) {
|
||||
return absl::InternalError("Failed to add keys");
|
||||
}
|
||||
}
|
||||
License::Policy license_policy = drmRequest.policy_overrides();
|
||||
WvPLPlaybackPolicy wvpl_playback_policy;
|
||||
wvpl_playback_policy.set_license_duration_seconds(
|
||||
license_policy.license_duration_seconds());
|
||||
session->set_policy(wvpl_playback_policy);
|
||||
status = session->GenerateLicense(&response);
|
||||
if (!status.ok()) {
|
||||
// TODO: b/329230518 - Sometimes error message is empty, needs investigation
|
||||
return absl::InternalError("Failed to generate license: " +
|
||||
status.error_message());
|
||||
} else {
|
||||
}
|
||||
return response;
|
||||
}
|
||||
} // namespace wvpl_sdk
|
||||
} // namespace video_widevine
|
||||
23
centos/tools/src/testing/cts/sdk/wvpl_sdk.h
Normal file
23
centos/tools/src/testing/cts/sdk/wvpl_sdk.h
Normal file
@@ -0,0 +1,23 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_TESTING_CTS_SDK_WVPL_SDK_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_TESTING_CTS_SDK_WVPL_SDK_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
|
||||
namespace video_widevine {
|
||||
namespace wvpl_sdk {
|
||||
|
||||
absl::StatusOr<std::string> HandleDrmLicenseRequest(std::string requestString);
|
||||
}
|
||||
} // namespace video_widevine
|
||||
|
||||
#endif // VIDEO_WIDEVINE_EXPORT_TESTING_CTS_SDK_WVPL_SDK_H_
|
||||
64
centos/tools/src/testing/cts/server/BUILD
Normal file
64
centos/tools/src/testing/cts/server/BUILD
Normal file
@@ -0,0 +1,64 @@
|
||||
########################################
|
||||
## Copyright 2024 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
|
||||
# Binary to run cts wvpl server
|
||||
|
||||
load("//tools/build_defs/pkg:google.bzl", "pkg_binary_with_runfiles")
|
||||
|
||||
cc_binary(
|
||||
name = "test_server",
|
||||
srcs = ["test_server.cc"],
|
||||
deps = [
|
||||
"//base",
|
||||
"//chubby/lib/public:lockservice",
|
||||
"//net/eventmanager",
|
||||
"//net/eventmanager:eventmanager_utils",
|
||||
"//net/grpc:grpc++",
|
||||
"//net/http:httpserverrequest",
|
||||
"//net/http2/server/lib/public:server",
|
||||
"//net/rpc",
|
||||
|
||||
"@abseil_repo//absl/functional:bind_front",
|
||||
"@abseil_repo//absl/log",
|
||||
"@abseil_repo//absl/log:check",
|
||||
"//third_party/grpc",
|
||||
"//third_party/grpc:grpc++",
|
||||
"//thread",
|
||||
"//util:error_space",
|
||||
"//sdk/external/cpp/wvpl/common:wvpl_types",
|
||||
"//sdk/external/cpp/wvpl/license_server_sdk:wvpl_environment",
|
||||
"//testing/cts/env:wvpl_env",
|
||||
"//testing/cts/sdk:wvpl_sdk",
|
||||
"//webutil/http",
|
||||
],
|
||||
)
|
||||
|
||||
pkg_binary_with_runfiles(
|
||||
name = "test_server_with_runfiles",
|
||||
binary = ":test_server",
|
||||
)
|
||||
|
||||
genmpm(
|
||||
# Name of the rule, as usual.
|
||||
name = "test_server_temporal_mpm",
|
||||
# List of files to include in the package.
|
||||
srcs = [":test_server"],
|
||||
# Temporal MPM option. This allows us to use this target with `blaze_label`
|
||||
# in the .borg file, as explained below.
|
||||
temporal = True,
|
||||
)
|
||||
|
||||
genmpm(
|
||||
name = "test_server_mpm",
|
||||
# MPM package name.
|
||||
package_name = "testing/cts/server/test_server",
|
||||
# List of files to include in the package.
|
||||
deps = [
|
||||
":test_server_with_runfiles",
|
||||
],
|
||||
)
|
||||
79
centos/tools/src/testing/cts/server/README.md
Normal file
79
centos/tools/src/testing/cts/server/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# CTS server setup
|
||||
|
||||
The CTS server setup directory contains the cc_binary needed to build and run
|
||||
the CTS server. Instructions on how to build this binary locally are below.
|
||||
|
||||
[TOC]
|
||||
|
||||
## Get cts resources
|
||||
|
||||
Resource files are the ones from jts_resources, currently only using the ones
|
||||
needed for server startup. To get the resource files run the following from this
|
||||
directory (cts/server):\
|
||||
`mkdir cts_resources`\
|
||||
`gsutil -m cp -r gs://blockbuster/jts_resources/* ./cts_resources`
|
||||
|
||||
only resources being used currently are:
|
||||
* cert_staging_google_com.der
|
||||
* private_key_staging_google_com.der
|
||||
|
||||
## Setup service account locally
|
||||
|
||||
Important:
|
||||
**do not upload the service account json file,**
|
||||
**it is only to be used locally.**
|
||||
|
||||
Download the service account json from the jts google cloud server.
|
||||
Copy file locally to following location:
|
||||
`testing/cts/published_devices/service_acc_cred.json`\
|
||||
JSON cred file must be this exact name/path as this is specified in the `BUILD`
|
||||
file for
|
||||
the server.
|
||||
|
||||
Run the following command to setup google default creds:\
|
||||
`export GOOGLE_APPLICATION_CREDENTIALS=testing/cts/common/cts_resources/dcsl-google.com_blockbuster-1154-5f30025abf26.json`
|
||||
|
||||
## Run server
|
||||
|
||||
Running the server: \
|
||||
`blaze run //testing/cts/server:test_server -- --logtostderr
|
||||
--port=10000`
|
||||
|
||||
Another option to run server if logs are very long: \
|
||||
`blaze run //testing/cts/server:test_server >
|
||||
cts_error_log.txt -- --port=10000`
|
||||
|
||||
## Run server on borg local
|
||||
|
||||
build your web server and mpm package:\
|
||||
```
|
||||
blaze mpm -c opt testing/cts/server:test_server_mpm
|
||||
```
|
||||
|
||||
check versions, latest one is at bottom\
|
||||
```
|
||||
mpm packageinfo --show_version_map testing/cts/server/test_server
|
||||
```
|
||||
|
||||
run following with the latest package version (or whichever you want)\
|
||||
```
|
||||
PACKAGE_VERSION_ID=1-1ae53a0e_03cacc13_1f05d096_3052174c_28367faa
|
||||
```
|
||||
|
||||
set live label\
|
||||
```
|
||||
mpm setlabel testing/cts/server/test_server --label=live --version=$PACKAGE_VERSION_ID
|
||||
```
|
||||
|
||||
start up borg\
|
||||
```
|
||||
borgcfg production/borg/widevine/templates/dev/cts_wvpl.borg --borguser=nihardamar --user=nihardamar up
|
||||
```
|
||||
|
||||
shut down borg job\
|
||||
```
|
||||
borgcfg production/borg/widevine/templates/dev/cts_wvpl.borg --borguser=nihardamar --user=nihardamar down
|
||||
```
|
||||
|
||||
Url to look up borg job\
|
||||
http://sigma
|
||||
82
centos/tools/src/testing/cts/server/test_server.cc
Normal file
82
centos/tools/src/testing/cts/server/test_server.cc
Normal file
@@ -0,0 +1,82 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2024 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/init_google.h"
|
||||
#include "net/eventmanager/eventmanager.h"
|
||||
#include "net/eventmanager/eventmanager_utils.h"
|
||||
#include "net/http/httpserverrequest.h"
|
||||
#include "net/http2/server/lib/public/httpserver2.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/functional/bind_front.h"
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "testing/cts/env/wvpl_env.h"
|
||||
#include "testing/cts/sdk/wvpl_sdk.h"
|
||||
#include "webutil/http/httpresponse.h"
|
||||
|
||||
using net_http2::HTTPServer2;
|
||||
using video_widevine::wvpl_sdk::HandleDrmLicenseRequest;
|
||||
|
||||
ABSL_FLAG(int32_t, port, 10000, "Port for incoming HTTP requests");
|
||||
ABSL_FLAG(int32_t, worker_threads, 10, "Number of worker threads");
|
||||
|
||||
void SDKHandler(HTTPServerRequest* req) {
|
||||
req->output()->WriteString("Hello world");
|
||||
req->Reply();
|
||||
}
|
||||
|
||||
// TODO: b/323916039 - Setup handlers to response to endpoints for SDK
|
||||
void drmRequestHandler(HTTPServerRequest* req) {
|
||||
std::string requestString = req->input()->ToString();
|
||||
absl::StatusOr<std::string> response = HandleDrmLicenseRequest(requestString);
|
||||
if (!response.ok()) {
|
||||
req->output()->WriteString(response.status().ToString());
|
||||
req->ReplyWithStatus(HTTPResponse::RC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
req->output()->WriteString(response.value());
|
||||
req->Reply();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
auto wvpl_env = video_widevine::cts::wvpl_env::WvplEnv::GetInstance();
|
||||
if (wvpl_env->env_setup_failed()) {
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
|
||||
// Configure the options for your server
|
||||
auto options = absl::make_unique<HTTPServer2::EventModeOptions>();
|
||||
options->SetVersion("Example HTTPServer2 (non-blocking)");
|
||||
options->SetServerType("test_server");
|
||||
options->AddPort(absl::GetFlag(FLAGS_port)); // Create the HTTPServer2
|
||||
|
||||
eventmanager::GenericEventManagerOptions eventOptions;
|
||||
eventOptions.num_threads_hint = absl::GetFlag(FLAGS_worker_threads);
|
||||
auto eventManager = eventmanager::NewEventManager(eventOptions);
|
||||
eventmanager::EventManagerInterface* eventManagerPtr = eventManager.get();
|
||||
|
||||
std::unique_ptr<HTTPServer2> server =
|
||||
HTTPServer2::CreateEventDrivenModeServer(eventManagerPtr,
|
||||
std::move(options))
|
||||
.value();
|
||||
server->RegisterHandler("/", absl::bind_front(SDKHandler));
|
||||
server->RegisterHandler("/drmRequest", absl::bind_front(drmRequestHandler));
|
||||
|
||||
CHECK_OK(server->StartAcceptingRequests());
|
||||
server->WaitForTermination();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
########################################
|
||||
## Copyright 2019 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
# Desciption:
|
||||
# JTS http clients.
|
||||
|
||||
load("@rules_java//java:defs.bzl", "java_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "httpclient",
|
||||
srcs = glob(
|
||||
["*.java"],
|
||||
exclude = [
|
||||
"CdmHttpClient.java",
|
||||
],
|
||||
),
|
||||
deps = [
|
||||
"@google_api//:com_google_api_client_google_api_client",
|
||||
"@google_guice//:com_google_inject_guice",
|
||||
"@google_http_client//:com_google_http_client_google_http_client",
|
||||
"@google_http_client_gson//:com_google_http_client_google_http_client_gson",
|
||||
"@google_oauth2//:com_google_oauth_client_google_oauth_client",
|
||||
"@jackson_core//:com_fasterxml_jackson_core_jackson_core",
|
||||
"@json//:org_json_json",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "cdm_http_client",
|
||||
srcs = ["CdmHttpClient.java"],
|
||||
deps = [
|
||||
"//java/com/google/chubby/svelte:bns_resolver",
|
||||
"//java/com/google/io/base",
|
||||
"//java/com/google/net/httpclient",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2019 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.httpclient;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* JTS Cloud Credentials.
|
||||
*
|
||||
* Provides Oauth2 authentication, and access/refresh tokens.
|
||||
*/
|
||||
public class Credentials {
|
||||
|
||||
private static final List<String> SCOPES = Arrays.asList(
|
||||
"https://www.googleapis.com/auth/cloud-platform",
|
||||
"https://www.googleapis.com/auth/widevine/frontend");
|
||||
private static final int MIN_ACCESS_TOKEN_REFRESH_SEC = 1200;
|
||||
private static final Logger logger = Logger.getLogger(Credentials.class.getName());
|
||||
|
||||
private String credentialsJsonFile = null;
|
||||
private GoogleCredential googleCredential = null;
|
||||
private String accessToken = null;
|
||||
|
||||
/**
|
||||
* Credentials Constructor.
|
||||
*
|
||||
* @param credentialsJsonFile The full path to a GCP service account json credentials file.
|
||||
*/
|
||||
public Credentials(String credentialsJsonFile) throws IOException {
|
||||
this.credentialsJsonFile = credentialsJsonFile;
|
||||
activateGoogleCredentials();
|
||||
}
|
||||
|
||||
private void activateGoogleCredentials() throws IOException {
|
||||
googleCredential = GoogleCredential
|
||||
.fromStream(new FileInputStream(credentialsJsonFile))
|
||||
.createScoped(SCOPES);
|
||||
googleCredential.refreshToken();
|
||||
}
|
||||
|
||||
/** Provides an Oauth2 Access Token that can be used to make GCP service calls.*/
|
||||
public String getAccessToken() throws IOException {
|
||||
if (accessToken == null
|
||||
|| googleCredential.getExpiresInSeconds() <= MIN_ACCESS_TOKEN_REFRESH_SEC) {
|
||||
googleCredential.refreshToken();
|
||||
accessToken = googleCredential.getAccessToken();
|
||||
logger.log(Level.INFO, "Getting new access token.");
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
########################################
|
||||
## Copyright 2018 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
# Desciption:
|
||||
# JTS interfaces.
|
||||
|
||||
load("@rules_java//java:defs.bzl", "java_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "interfaces",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:device_security_profiles_java_proto",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto",
|
||||
"@com_google_protobuf//:protobuf_java",
|
||||
"@apache_httpcore//:org_apache_httpcomponents_httpcore",
|
||||
"//protos/public:license_protocol_java_proto",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2019 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.interfaces;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices;
|
||||
|
||||
/**
|
||||
* DeviceCertificate defines APIs for getting PublishedDevices and Published Devices list.
|
||||
*/
|
||||
public interface DeviceCertificate {
|
||||
|
||||
/**
|
||||
* Get the latest {@code PublishedDevices} containing Published Devices list data.
|
||||
*
|
||||
* @return {@code PublishedDevices} containing Published Devices list data.
|
||||
*/
|
||||
public PublishedDevices getPublishedDevices() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.interfaces;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.SignedDeviceSecurityProfiles;
|
||||
|
||||
/** DeviceSecurityProfile defines APIs for getting Signed Device Security Profile list. */
|
||||
public interface DeviceSecurityProfile {
|
||||
|
||||
/**
|
||||
* Get the latest {@code SignedDeviceSecurityProfiles} containing Device Security Profile list
|
||||
* data.
|
||||
*
|
||||
* @return {@code SignedDeviceSecurityProfiles} containing Device Security Profile list data.
|
||||
*/
|
||||
public SignedDeviceSecurityProfiles getSignedDeviceSecurityProfiles() throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2023 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.interfaces;
|
||||
|
||||
/**
|
||||
* IndividualDeviceRevocationList defines APIs for getting Individual Device Revocation List (IDRL).
|
||||
*/
|
||||
public interface IndividualDeviceRevocationList {
|
||||
|
||||
/**
|
||||
* Get the latest Individual Device Revocation List data.
|
||||
*
|
||||
* @return Individual Device Revocation List data.
|
||||
*/
|
||||
public byte[] getIndividualDeviceRevocationList() throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2018 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.interfaces;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.video.widevine.protos.LicenseProtocol.License.KeyContainer;
|
||||
import java.util.List;
|
||||
|
||||
/** An interface to be implemented by a Key provider. */
|
||||
public interface KeyProviderInterface {
|
||||
/**
|
||||
* Gets a list of KeyContainers for the specified content Id.
|
||||
*
|
||||
* @param contentId The content Id that uniquely identifies the video.
|
||||
* Cannot be used in conjunction with keyIds.
|
||||
* See http://google3/protos/public/widevine_pssh.proto
|
||||
* @return A List of KeyContainer protos if the content is found, else null.
|
||||
*/
|
||||
public List<KeyContainer> getKeys(String contentId);
|
||||
|
||||
/**
|
||||
* Gets a list of KeyContainers for the specified key Ids.
|
||||
* @param keyIds The key Ids to apply to a video's license.
|
||||
* Cannot be used in conjunction with contentId.
|
||||
* See http://google3/protos/public/widevine_pssh.proto
|
||||
* @return A List of KeyContainer protos if the key IDs are found, else null.
|
||||
*/
|
||||
public List<KeyContainer> getKeys(List<ByteString> keyIds);
|
||||
|
||||
/**
|
||||
* Gets a list of KeyContainers for the specified List of DSP names.
|
||||
* @param dspNames The DSP names to fetch associated KeyContainers.
|
||||
* @return A List of KeyContainer protos if the DSPs are found, else returns empty List
|
||||
* if no DSPs found.
|
||||
*/
|
||||
public List<KeyContainer> getKeysFromDsp(List<String> dspNames);
|
||||
|
||||
/**
|
||||
* Gets a profile name that is associated with the keyId and contentOwner.
|
||||
*
|
||||
* @param keyId The key Ids to apply to a video's license.
|
||||
* @param contentOwner The content owner of the key.
|
||||
* @return A profile name if the keyId and contentOwner are found, else returns empty string.
|
||||
*/
|
||||
public String getRequiredDspProfileForKeyId(String keyId, String contentOwner);
|
||||
|
||||
/** Returns the owner of the DSP. */
|
||||
public String getOwnerForDsp();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2018 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.interfaces;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
/**
|
||||
* LicenseInterface defines the API that a license-based SDK must implement.
|
||||
*
|
||||
* <p>The {@link LicenseRequestAction} receives all incoming license requests and dispatches them to
|
||||
* the appropriate licensing service SDK implementation for processing. This interface defines the
|
||||
* API that each SDK implementation must provide in order for requests to be properly handled.
|
||||
*/
|
||||
public interface LicenseInterface {
|
||||
|
||||
/**
|
||||
* Handles an incoming license request and returns the license response.
|
||||
*
|
||||
* @param requestBody The incoming body of the license request.
|
||||
* @param policyId Optional. A custom policy ID to use if specified, else null.
|
||||
* @param renewalPolicyId Optional. A custom renewal policy ID to use if specified, else null.
|
||||
* @param requestId A unique request id used to track, or collect stats on, a specific request, or
|
||||
* series of requests.
|
||||
* @param useDsp Set {@code true} to process license using Device Security Profiles (DSP).
|
||||
* @param useFilterKey Set {@code true} to using filterKey() to insert keys in license request.
|
||||
* @return The license response to be returned to the client as a byte[].
|
||||
*/
|
||||
public byte[] handleLicenseRequest(
|
||||
byte[] requestBody,
|
||||
String policyId,
|
||||
String renewalPolicyId,
|
||||
String requestId,
|
||||
boolean useDsp,
|
||||
boolean useFilterKey,
|
||||
StringBuilder sessionUsageBuilder)
|
||||
throws HttpException;
|
||||
|
||||
/** Handles returning status info about a running SDK. */
|
||||
public byte[] getSdkStatus();
|
||||
|
||||
/**
|
||||
* Handles an incoming DrmLicenseRequest and returns the license response.
|
||||
*
|
||||
* @param requestBody The incoming body of the ModularDrmLicenseRequest or CasDrmLicenseRequest.
|
||||
* @param useDsp Set {@code true} to process license using Device Security Profiles (DSP).
|
||||
* @param useFilterKey Set {@code true} to using filterKey() to insert keys in license request.
|
||||
* @return The license response to be returned to the client as a byte[].
|
||||
*/
|
||||
public byte[] handleDrmLicenseRequest(byte[] requestBody, boolean useDsp, boolean useFilterKey)
|
||||
throws HttpException;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2018 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.interfaces;
|
||||
|
||||
import com.google.video.widevine.protos.LicenseProtocol.License.Policy;
|
||||
|
||||
// TODO(march): Move back to /j/c/g/v/w/testing/sdk/interfaces once b/79438055 is fixed.
|
||||
|
||||
/** An interface to be implemented by a Policy provider. */
|
||||
public interface PolicyProviderInterface {
|
||||
/**
|
||||
* Gets a Policy for the specified policy ID.
|
||||
*
|
||||
* @param policyId The ID of the policy to retrieve.
|
||||
* @return A Policy proto if the policy is found, else null.
|
||||
*/
|
||||
public Policy getPolicy(String policyId);
|
||||
|
||||
/**
|
||||
* Gets a policy id for the specified content id.
|
||||
*
|
||||
* @param contentId The id of the content to retrieve.
|
||||
* @return The policy id if the content is found and has a policy, else null.
|
||||
*/
|
||||
public String getPolicyIdForContentId(String contentId);
|
||||
|
||||
/**
|
||||
* Gets a Provider Session Token (PST) for the specified content id.
|
||||
*
|
||||
* @param contentId The id of the content to retrieve.
|
||||
* @return The PST token if the content is found and has uses one.
|
||||
*/
|
||||
public String getProviderSessionToken(String contentId);
|
||||
|
||||
/**
|
||||
* Sets a Policy for the specified policy ID.
|
||||
*
|
||||
* @param policyId The ID of the policy to set.
|
||||
* @param policy A proto defining the policy details.
|
||||
* @return A boolean indicating whether the policy was successfully set.
|
||||
*/
|
||||
public Boolean setPolicy(String policyId, Policy policy);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
########################################
|
||||
## Copyright 2018 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
# Description:
|
||||
# JTS interfaces.
|
||||
|
||||
load("@rules_java//java:defs.bzl", "java_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "providers",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:device_security_profiles_java_proto",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_grpc",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto",
|
||||
"//google/chrome/widevine/frauddetection/v1eap1:fraud_detection_and_reporting_grpc",
|
||||
"//google/chrome/widevine/frauddetection/v1eap1:fraud_detection_and_reporting_service_java_proto",
|
||||
"//protos/public:device_certificate_status_java_proto",
|
||||
"//protos/public:license_protocol_java_proto",
|
||||
"//protos/public:sdk_license_data_config_java_proto",
|
||||
"//protos/public:widevine_pssh_java_proto",
|
||||
":libwidevine_license_wvpl_sdk_lib.jar",
|
||||
"//testing/java/com/google/video/widevine/jts/common",
|
||||
"//testing/java/com/google/video/widevine/jts/httpclient",
|
||||
"//testing/java/com/google/video/widevine/jts/interfaces",
|
||||
"@com_google_protobuf//:protobuf_java",
|
||||
"@com_google_protobuf//:timestamp_proto",
|
||||
"@google_guava//:com_google_guava_guava",
|
||||
"@google_guice//:com_google_inject_guice",
|
||||
"@io_grpc_grpc_java//api",
|
||||
"@io_grpc_grpc_java//netty",
|
||||
"@io_grpc_grpc_java//stub",
|
||||
"@json//:org_json_json",
|
||||
"@maven//:com_google_api_grpc_proto_google_common_protos",
|
||||
"@maven//:com_google_code_findbugs_jsr305",
|
||||
"@maven//:com_google_code_gson_gson",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "providers_tools",
|
||||
srcs = [
|
||||
"PublishedDevicesProvider.java",
|
||||
],
|
||||
deps = [
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:device_security_profiles_java_proto",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_grpc",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto",
|
||||
"//google/chrome/widevine/frauddetection/v1eap1:fraud_detection_and_reporting_grpc",
|
||||
"//google/chrome/widevine/frauddetection/v1eap1:fraud_detection_and_reporting_service_java_proto",
|
||||
"//protos/public:device_certificate_status_java_proto",
|
||||
":libwidevine_license_wvpl_sdk_lib.jar",
|
||||
"//testing/java/com/google/video/widevine/jts/httpclient",
|
||||
"//testing/java/com/google/video/widevine/jts/interfaces",
|
||||
"@com_google_protobuf//:protobuf_java",
|
||||
"@com_google_protobuf//:timestamp_proto",
|
||||
"@google_guava//:com_google_guava_guava",
|
||||
"@google_guice//:com_google_inject_guice",
|
||||
"@io_grpc_grpc_java//api",
|
||||
"@io_grpc_grpc_java//netty",
|
||||
"@io_grpc_grpc_java//stub",
|
||||
"@maven//:com_google_code_findbugs_jsr305",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,339 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
package com.google.video.widevine.jts.providers;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.DcslSnapshotType;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.DeviceSecurityProfileCriteria;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.ListDeviceSecurityProfilesRequest;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevicesRequest;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevicesServiceGrpc;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.RetrieveIndividualDeviceRevocationListRequest;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.RetrieveIndividualDeviceRevocationListResponse;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.SignedDeviceSecurityProfiles;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.FraudDetectionAndReportingServiceGrpc;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.FraudLevel;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.LicenseRequestInfo;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.LicenseRequestInfo.RequestMetadata;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.ReportFraudLevelRequest;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.ReportFraudLevelResponse;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.ExtensionRegistry;
|
||||
import com.google.protobuf.TextFormat;
|
||||
import com.google.protobuf.Timestamp;
|
||||
import com.google.video.widevine.jts.httpclient.Credentials;
|
||||
import com.google.video.widevine.jts.interfaces.DeviceCertificate;
|
||||
import com.google.video.widevine.jts.interfaces.DeviceSecurityProfile;
|
||||
import com.google.video.widevine.jts.interfaces.IndividualDeviceRevocationList;
|
||||
import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatusList;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLBaseEnvironment;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatusException;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.netty.NettyChannelBuilder;
|
||||
import io.grpc.stub.MetadataUtils;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Provides the latest {@code PublishedDevices} or {@code SignedDeviceSecurityProfiles} data from
|
||||
* the Widevine Published Devices Service.
|
||||
*
|
||||
* <p>This implementation uses the Widevine Published Devices API, and support a gRPC method for
|
||||
* retrieving PublishedDevices with an embedded Published Devices list, or Device Security Profiles
|
||||
* list.
|
||||
*/
|
||||
public class PublishedDevicesProvider
|
||||
implements DeviceCertificate, DeviceSecurityProfile, IndividualDeviceRevocationList {
|
||||
private static final Logger logger = Logger.getLogger(PublishedDevicesProvider.class.getName());
|
||||
private WvPLBaseEnvironment<?> environment = null;
|
||||
private String apiServicePath = null;
|
||||
private Credentials credentials = null;
|
||||
private String provider = null;
|
||||
private boolean includeImpactAnalysis = false;
|
||||
private Integer lastDcslEpochTime = null;
|
||||
private String dcslType = null;
|
||||
private static final String FRAUDULENT_API_SERVICE_PATH = "widevinefrauddetection.googleapis.com";
|
||||
|
||||
/**
|
||||
* PublishedDevicesProvider constructor.
|
||||
*
|
||||
* @param environment A WvPLBaseEnvironment object initialized with a Service Certificate.
|
||||
* @param serviceAccountPath Path to a GCP Service Account json file, used in OAUTH.
|
||||
* @param apiServicePath Path to a Widevine Published Devices API service.
|
||||
* @param provider Provider name, necessary for creating ListDSP request. It could be null if it
|
||||
* is not used by dsps.
|
||||
* @param includeImpactAnalysis Includes impact analysis in published devices response based on
|
||||
* flag value. It can be false if caller doesn't care about impact analysis data from
|
||||
* published devices.
|
||||
* @param lastDcslEpochTime Timestamp that helps to calculate the DCSL impact analysis from a DCSL
|
||||
* snapshot at last_dcsl_epoch_time to the latest DCSL snapshot. It can be set to null if
|
||||
* caller doesn't care about impact analysis data from published devices.
|
||||
* @throws IOException upon failure creating OAUTH credentials.
|
||||
*/
|
||||
@Inject
|
||||
public PublishedDevicesProvider(
|
||||
WvPLBaseEnvironment<?> environment,
|
||||
String serviceAccountPath,
|
||||
String apiServicePath,
|
||||
@Nullable String provider,
|
||||
boolean includeImpactAnalysis,
|
||||
Integer lastDcslEpochTime,
|
||||
String dcslType)
|
||||
throws IOException {
|
||||
this.environment = environment;
|
||||
this.apiServicePath = apiServicePath;
|
||||
credentials = new Credentials(serviceAccountPath);
|
||||
this.provider = provider;
|
||||
this.includeImpactAnalysis = includeImpactAnalysis;
|
||||
this.lastDcslEpochTime = lastDcslEpochTime;
|
||||
this.dcslType = dcslType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest {@code PublishedDevices} from the Widevine Published Devices Service.
|
||||
*
|
||||
* @return The latest {@code PublishedDevices} data.
|
||||
* @throws InterruptedException upon RPC failure.
|
||||
* @throws WvPLStatusException upon WvPLBaseEnvironment errors.
|
||||
*/
|
||||
@Override
|
||||
public PublishedDevices getPublishedDevices() throws InterruptedException, WvPLStatusException {
|
||||
ManagedChannel channel = null;
|
||||
PublishedDevices devicesResponse = null;
|
||||
|
||||
logger.log(Level.INFO, "Getting PublishedDevices...");
|
||||
try {
|
||||
channel = createRpcChannel(apiServicePath);
|
||||
PublishedDevicesServiceGrpc.PublishedDevicesServiceBlockingStub blockingStub =
|
||||
createBlockingStub(channel);
|
||||
PublishedDevicesRequest publishedDevicesRequest =
|
||||
PublishedDevicesRequest.parseFrom(
|
||||
environment.generateDeviceStatusListRequest(), ExtensionRegistry.getEmptyRegistry());
|
||||
PublishedDevicesRequest.Builder updatedPublishedDevicesRequestBuilder =
|
||||
publishedDevicesRequest.toBuilder().setIncludeImpactAnalysis(includeImpactAnalysis);
|
||||
if (lastDcslEpochTime != null) {
|
||||
updatedPublishedDevicesRequestBuilder.setLastDcslEpochTime(
|
||||
Timestamp.newBuilder().setSeconds(lastDcslEpochTime).build());
|
||||
}
|
||||
updatedPublishedDevicesRequestBuilder.setDcslSnapshotType(getDcslSnapshotType(dcslType));
|
||||
devicesResponse =
|
||||
blockingStub.getPublishedDevices(updatedPublishedDevicesRequestBuilder.build());
|
||||
String truncatedLogString = TextFormat.printer().printToString(devicesResponse);
|
||||
int tenLines = 800;
|
||||
if (truncatedLogString.length() > tenLines) {
|
||||
truncatedLogString = truncatedLogString.substring(0, tenLines) + "...";
|
||||
}
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"GRPC Call to PublishedDevicesService.GetPublishedDevices returned:\n"
|
||||
+ truncatedLogString);
|
||||
|
||||
DeviceCertificateStatusList dcsl =
|
||||
DeviceCertificateStatusList.parseFrom(
|
||||
devicesResponse.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry());
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"Impact analysis count in response from PublishedDevicesService.GetPublishedDevices is:\n"
|
||||
+ dcsl.getImpactAnalysisReport().getImpactAnalysisCount());
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"DCSL type in response from PublishedDevicesService.GetPublishedDevices is:\n"
|
||||
+ devicesResponse.getDcslSnapshotType());
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"DCSL snapshot creation time in response from"
|
||||
+ " PublishedDevicesService.GetPublishedDevices is: "
|
||||
+ dcsl.getCreationTimeSeconds()
|
||||
+ " in UTC time is :\n"
|
||||
+ Instant.ofEpochSecond(dcsl.getCreationTimeSeconds())
|
||||
.atZone(ZoneOffset.UTC)
|
||||
.toLocalDateTime()
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.INFO, "IOException encountered trying to retrieve the signed list: " + e);
|
||||
} finally {
|
||||
closeRpcChannel(channel);
|
||||
}
|
||||
return devicesResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignedDeviceSecurityProfiles getSignedDeviceSecurityProfiles()
|
||||
throws InterruptedException, WvPLStatusException {
|
||||
// Generate list dsp request.
|
||||
ListDeviceSecurityProfilesRequest listDspRequest =
|
||||
ListDeviceSecurityProfilesRequest.newBuilder()
|
||||
.setDeviceSecurityProfileCriteria(
|
||||
DeviceSecurityProfileCriteria.newBuilder()
|
||||
.setContentProvider(this.provider)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
ManagedChannel channel = null;
|
||||
SignedDeviceSecurityProfiles signedMessageInResponse = null;
|
||||
|
||||
logger.log(Level.INFO, "Getting DeviceSecurityProfilesList...");
|
||||
try {
|
||||
channel = createRpcChannel(apiServicePath);
|
||||
PublishedDevicesServiceGrpc.PublishedDevicesServiceBlockingStub blockingStub =
|
||||
createBlockingStub(channel);
|
||||
|
||||
signedMessageInResponse =
|
||||
blockingStub.listDeviceSecurityProfiles(listDspRequest).getSignedDeviceSecurityProfiles();
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"GRPC Call to PublishedDevicesService.ListDeviceSecurityProfiles returned:\n"
|
||||
+ TextFormat.printer().printToString(signedMessageInResponse));
|
||||
} catch (IOException e) {
|
||||
logger.log(
|
||||
Level.INFO, "IOException encountered trying to retrieve the signed dsp list: " + e);
|
||||
} finally {
|
||||
closeRpcChannel(channel);
|
||||
}
|
||||
return signedMessageInResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getIndividualDeviceRevocationList() throws InterruptedException {
|
||||
ManagedChannel channel = null;
|
||||
RetrieveIndividualDeviceRevocationListResponse response = null;
|
||||
logger.log(Level.INFO, "Getting IndividualDeviceRevocationList...");
|
||||
try {
|
||||
channel = createRpcChannel(apiServicePath);
|
||||
PublishedDevicesServiceGrpc.PublishedDevicesServiceBlockingStub blockingStub =
|
||||
createBlockingStub(channel);
|
||||
RetrieveIndividualDeviceRevocationListRequest request =
|
||||
RetrieveIndividualDeviceRevocationListRequest.newBuilder()
|
||||
.setProvider(this.provider)
|
||||
.build();
|
||||
response = blockingStub.retrieveIndividualDeviceRevocationList(request);
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"GRPC Call to PublishedDevicesService.retrieveIndividualDeviceRevocationList returned:\n"
|
||||
+ TextFormat.printer().printToString(response));
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.INFO, "IOException encountered trying to retrieve the IDRL: " + e);
|
||||
} finally {
|
||||
closeRpcChannel(channel);
|
||||
}
|
||||
return response.toByteArray();
|
||||
}
|
||||
|
||||
public byte[] reportFraudulentDevice(
|
||||
String licenseRequest,
|
||||
@Nullable String clearClientId,
|
||||
@Nullable String userAgent,
|
||||
@Nullable String reason,
|
||||
FraudLevel.FraudScore fraudScore)
|
||||
throws InterruptedException, IOException {
|
||||
ReportFraudLevelRequest request =
|
||||
createReportFraudLevelRequest(
|
||||
this.provider, licenseRequest, clearClientId, userAgent, reason, fraudScore);
|
||||
ManagedChannel channel = createRpcChannel(FRAUDULENT_API_SERVICE_PATH);
|
||||
try {
|
||||
return reportFraudulentDeviceWithChannel(channel, request);
|
||||
} finally {
|
||||
closeRpcChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the ReportFraudLevelRequest.
|
||||
static ReportFraudLevelRequest createReportFraudLevelRequest(
|
||||
String provider,
|
||||
String licenseRequest,
|
||||
@Nullable String clearClientId,
|
||||
@Nullable String userAgent,
|
||||
@Nullable String reason,
|
||||
FraudLevel.FraudScore fraudScore) {
|
||||
RequestMetadata.Builder requestMetadata = RequestMetadata.newBuilder().setProvider(provider);
|
||||
if (userAgent != null) {
|
||||
requestMetadata.setUserAgent(userAgent);
|
||||
}
|
||||
LicenseRequestInfo.Builder licenseRequestInfo =
|
||||
LicenseRequestInfo.newBuilder()
|
||||
.setRequestMetadata(requestMetadata.build())
|
||||
.setLicenseRequest(ByteString.copyFrom(Base64.getDecoder().decode(licenseRequest)));
|
||||
if (clearClientId != null) {
|
||||
licenseRequestInfo.setClearClientId(
|
||||
ByteString.copyFrom(Base64.getDecoder().decode(clearClientId)));
|
||||
}
|
||||
ReportFraudLevelRequest.Builder request =
|
||||
ReportFraudLevelRequest.newBuilder()
|
||||
.setFraudLevel(FraudLevel.newBuilder().setFraudScore(fraudScore))
|
||||
.setLicenseRequestInfo(licenseRequestInfo.build());
|
||||
if (reason != null) {
|
||||
request.setReason(reason);
|
||||
}
|
||||
return request.build();
|
||||
}
|
||||
|
||||
private byte[] reportFraudulentDeviceWithChannel(
|
||||
ManagedChannel channel, ReportFraudLevelRequest request) throws IOException {
|
||||
logger.log(Level.INFO, "Reporting fraudulent device...");
|
||||
FraudDetectionAndReportingServiceGrpc.FraudDetectionAndReportingServiceBlockingStub
|
||||
blockingStub =
|
||||
FraudDetectionAndReportingServiceGrpc.newBlockingStub(channel)
|
||||
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(createMetadata()));
|
||||
ReportFraudLevelResponse response = blockingStub.reportFraudLevel(request);
|
||||
logger.log(
|
||||
Level.INFO,
|
||||
"GRPC Call to report fraud returned:\n" + TextFormat.printer().printToString(response));
|
||||
return response.toByteArray();
|
||||
}
|
||||
|
||||
private static ManagedChannel createRpcChannel(String host) {
|
||||
return NettyChannelBuilder.forTarget(host).build();
|
||||
}
|
||||
|
||||
private static void closeRpcChannel(ManagedChannel channel) throws InterruptedException {
|
||||
if (channel != null) {
|
||||
channel.shutdown();
|
||||
channel.awaitTermination(1, SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private Metadata createMetadata() throws IOException {
|
||||
Metadata metadata = new Metadata();
|
||||
String token = "Bearer " + credentials.getAccessToken();
|
||||
metadata.put(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER), token);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private PublishedDevicesServiceGrpc.PublishedDevicesServiceBlockingStub createBlockingStub(
|
||||
ManagedChannel channel) throws IOException {
|
||||
Metadata metadata = createMetadata();
|
||||
return PublishedDevicesServiceGrpc.newBlockingStub(channel)
|
||||
.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));
|
||||
}
|
||||
|
||||
private DcslSnapshotType getDcslSnapshotType(String dcslType) throws IOException {
|
||||
if (dcslType == null) {
|
||||
return DcslSnapshotType.DCSL_SNAPSHOT_TYPE_UNSPECIFIED;
|
||||
} else if (Ascii.equalsIgnoreCase(dcslType, "alpha")) {
|
||||
return DcslSnapshotType.DCSL_ALPHA;
|
||||
} else if (Ascii.equalsIgnoreCase(dcslType, "beta")) {
|
||||
return DcslSnapshotType.DCSL_BETA;
|
||||
} else if (Ascii.equalsIgnoreCase(dcslType, "released")) {
|
||||
return DcslSnapshotType.DCSL_RELEASED;
|
||||
}
|
||||
throw new IOException(
|
||||
"Invalid value set for dcslType flag. Valid values are Alpha, Beta and Released.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
########################################
|
||||
## Copyright 2019 Google LLC
|
||||
##
|
||||
## This software is licensed under the terms defined in the Widevine Master
|
||||
## License Agreement. For a copy of this agreement, please contact
|
||||
## widevine-licensing@google.com.
|
||||
########################################
|
||||
# Description:
|
||||
# JTS tools.
|
||||
|
||||
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
java_library(
|
||||
name = "published_devices_cli_lib",
|
||||
srcs = [
|
||||
"PublishedDevicesCli.java",
|
||||
],
|
||||
deps = [
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:device_security_profiles_java_proto",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_grpc",
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto",
|
||||
"//google/chrome/widevine/frauddetection/v1eap1:fraud_detection_and_reporting_service_java_proto",
|
||||
"//testing/java/com/google/video/widevine/jts/providers:libwidevine_license_wvpl_sdk_lib.jar",
|
||||
"//testing/java/com/google/video/widevine/jts/providers:providers_tools",
|
||||
"@google_guava//:com_google_guava_guava",
|
||||
"@jcommander//:com_beust_jcommander",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "published_devices_delta_lib",
|
||||
srcs = [
|
||||
"PublishedDevicesDeltaWrapper.java",
|
||||
"PublishedDevicesWrapper.java",
|
||||
],
|
||||
deps = [
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto",
|
||||
"//protos/public:device_certificate_status_java_proto",
|
||||
"//protos/public:device_certificate_status_proto",
|
||||
"//protos/public:published_devices_delta_java_proto",
|
||||
"//protos/public:published_devices_delta_proto",
|
||||
"@com_google_protobuf//:protobuf_java",
|
||||
"@google_guava//:com_google_guava_guava",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "device_security_profiles_lib",
|
||||
srcs = [
|
||||
"DeviceSecurityProfilesDeltaWrapper.java",
|
||||
"DeviceSecurityProfilesWrapper.java",
|
||||
],
|
||||
deps = [
|
||||
"//google/chrome/widevine/contentpartners/v1beta1:device_security_profiles_java_proto",
|
||||
"//protos/public:device_security_profile_list_java_proto",
|
||||
"//protos/public:device_security_profiles_delta_java_proto",
|
||||
"//protos/public:security_profile_java_proto",
|
||||
"@com_google_protobuf//:protobuf_java",
|
||||
"@google_guava//:com_google_guava_guava",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "published_devices_cli",
|
||||
main_class = "com.google.video.widevine.jts.tools.PublishedDevicesCli",
|
||||
runtime_deps = [
|
||||
":published_devices_cli_lib",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "published_devices_delta",
|
||||
main_class = "com.google.video.widevine.jts.tools.PublishedDevicesMain",
|
||||
runtime_deps = [
|
||||
":published_devices_delta_main_lib",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "published_devices_delta_main_lib",
|
||||
srcs = [
|
||||
"PublishedDevicesMain.java",
|
||||
],
|
||||
deps = [
|
||||
":device_security_profiles_lib",
|
||||
":published_devices_delta_lib",
|
||||
"//protos/public:device_certificate_status_java_proto",
|
||||
"//protos/public:device_certificate_status_proto",
|
||||
"//protos/public:device_security_profiles_delta_java_proto",
|
||||
"//protos/public:device_security_profiles_delta_proto",
|
||||
"//protos/public:published_devices_delta_java_proto",
|
||||
"//protos/public:published_devices_delta_proto",
|
||||
"//protos/public:security_profile_java_proto",
|
||||
"@com_google_protobuf//:protobuf_java",
|
||||
"@google_guava//:com_google_guava_guava",
|
||||
"@jcommander//:com_beust_jcommander",
|
||||
"@json//:org_json_json",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,265 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.SignedDeviceSecurityProfiles;
|
||||
import com.google.protobuf.ExtensionRegistry;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfileListProtos.DeviceSecurityProfileList;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta.DspDelta;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta.Header;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta.Modified;
|
||||
import com.google.video.widevine.protos.SecurityProfileProtos.SecurityProfile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Device Security Profiles Delta Wrapper class to find the diff of two DSPs list. */
|
||||
final class DeviceSecurityProfilesDeltaWrapper {
|
||||
private DeviceSecurityProfileList originalDspList = null;
|
||||
private DeviceSecurityProfileList newDspList = null;
|
||||
private DeviceSecurityProfilesDelta dspDelta = null;
|
||||
private final List<SecurityProfile> dspAddedList = new ArrayList<>();
|
||||
private final List<SecurityProfile> dspRemovedList = new ArrayList<>();
|
||||
private final List<Modified> dspModifiedList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* DeviceSecurityProfilesDeltaWrapper constructor. The input is two {@link
|
||||
* SignedDeviceSecurityProfiles} proto messages.
|
||||
*
|
||||
* @param signedDspList1 first {@link SignedDeviceSecurityProfiles} proto message.
|
||||
* @param signedDspList2 second {@link SignedDeviceSecurityProfiles} proto message.
|
||||
* @throws InvalidProtocolBufferException if failed to parse DeviceSecurityProfileList from {@link
|
||||
* SignedDeviceSecurityProfiles}.
|
||||
*/
|
||||
public DeviceSecurityProfilesDeltaWrapper(
|
||||
SignedDeviceSecurityProfiles signedDspList1, SignedDeviceSecurityProfiles signedDspList2)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(signedDspList1, "'signedDspList1' must not be null");
|
||||
checkNotNull(signedDspList2, "'signedDspList2' must not be null");
|
||||
parseDeviceSecurityProfilesList(signedDspList1, signedDspList2);
|
||||
this.dspDelta = createDeviceSecurityProfilesDelta(originalDspList, newDspList);
|
||||
createDeviceSecurityProfilesDeltaInfo(this.dspDelta);
|
||||
}
|
||||
/**
|
||||
* DeviceSecurityProfilesDeltaWrapper constructor. The input is two byte arrays of serialized
|
||||
* {@link SignedDeviceSecurityProfiles} proto.
|
||||
*
|
||||
* @param signedDspListInBytes1 first serialized {@link SignedDeviceSecurityProfiles} proto in
|
||||
* bytes.
|
||||
* @param signedDspListInBytes2 second serialized {@link SignedDeviceSecurityProfiles} proto in
|
||||
* bytes.
|
||||
* @throws InvalidProtocolBufferException if failed to parse {@link SignedDeviceSecurityProfiles}
|
||||
* or if failed to parse {@link DeviceSecurityProfileList}.
|
||||
*/
|
||||
public DeviceSecurityProfilesDeltaWrapper(
|
||||
byte[] signedDspListInBytes1, byte[] signedDspListInBytes2)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(signedDspListInBytes1, "'signedDspListInBytes1' must not be null");
|
||||
checkNotNull(signedDspListInBytes2, "'signedDspListInBytes2' must not be null");
|
||||
SignedDeviceSecurityProfiles signedDspListProto1 =
|
||||
SignedDeviceSecurityProfiles.parseFrom(
|
||||
signedDspListInBytes1, ExtensionRegistry.getEmptyRegistry());
|
||||
SignedDeviceSecurityProfiles signedDspListProto2 =
|
||||
SignedDeviceSecurityProfiles.parseFrom(
|
||||
signedDspListInBytes2, ExtensionRegistry.getEmptyRegistry());
|
||||
parseDeviceSecurityProfilesList(signedDspListProto1, signedDspListProto2);
|
||||
this.dspDelta = createDeviceSecurityProfilesDelta(originalDspList, newDspList);
|
||||
createDeviceSecurityProfilesDeltaInfo(this.dspDelta);
|
||||
}
|
||||
|
||||
/** Returns {@link DeviceSecurityProfilesDelta} of two dsp lists. */
|
||||
public DeviceSecurityProfilesDelta getDelta() {
|
||||
return dspDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link DspDelta} for a specific content owner. If no matched result, return empty
|
||||
* DspDelta proto.
|
||||
*/
|
||||
public DspDelta getDeviceSecurityProfilesDelta(String owner) {
|
||||
for (DspDelta dspDeltaEntry : dspDelta.getDspDeltaList()) {
|
||||
if (dspDeltaEntry.getOwner().equals(owner)) {
|
||||
return dspDeltaEntry;
|
||||
}
|
||||
}
|
||||
return DspDelta.getDefaultInstance();
|
||||
}
|
||||
|
||||
/** Returns a list of added DSPs from DeviceSecurityProfilesDelta for all content owners. */
|
||||
public List<SecurityProfile> getAddedDeviceSecurityProfiles() {
|
||||
return dspAddedList;
|
||||
}
|
||||
|
||||
/** Returns a list of removed DSPs from DeviceSecurityProfilesDelta for all content owners. */
|
||||
public List<SecurityProfile> getRemovedDeviceSecurityProfiles() {
|
||||
return dspRemovedList;
|
||||
}
|
||||
|
||||
/** Returns a list of modified DSPs from DeviceSecurityProfilesDelta for all content owners. */
|
||||
public List<Modified> getModifiedDeviceSecurityProfiles() {
|
||||
return dspModifiedList;
|
||||
}
|
||||
|
||||
/** Parse {@link DeviceSecurityProfileList} from {@link SignedDeviceSecurityProfiles}. */
|
||||
private void parseDeviceSecurityProfilesList(
|
||||
SignedDeviceSecurityProfiles signedDspList1, SignedDeviceSecurityProfiles signedDspList2)
|
||||
throws InvalidProtocolBufferException {
|
||||
originalDspList =
|
||||
DeviceSecurityProfileList.parseFrom(
|
||||
signedDspList1.getDeviceSecurityProfiles(), ExtensionRegistry.getEmptyRegistry());
|
||||
newDspList =
|
||||
DeviceSecurityProfileList.parseFrom(
|
||||
signedDspList2.getDeviceSecurityProfiles(), ExtensionRegistry.getEmptyRegistry());
|
||||
|
||||
// Swap the DeviceSecurityProfileList if originalDspList is newer than signedDspList2.
|
||||
if (originalDspList.getCreationTimeSeconds() > newDspList.getCreationTimeSeconds()) {
|
||||
DeviceSecurityProfileList tempList = newDspList;
|
||||
newDspList = originalDspList;
|
||||
originalDspList = tempList;
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a {@link DeviceSecurityProfilesDelta} of originalDspList and newDspList. */
|
||||
private static DeviceSecurityProfilesDelta createDeviceSecurityProfilesDelta(
|
||||
DeviceSecurityProfileList originalDspList, DeviceSecurityProfileList newDspList) {
|
||||
Header header =
|
||||
Header.newBuilder()
|
||||
.setPrevCreationTimeSeconds(originalDspList.getCreationTimeSeconds())
|
||||
.setNewCreationTimeSeconds(newDspList.getCreationTimeSeconds())
|
||||
.build();
|
||||
DeviceSecurityProfilesDelta.Builder deltaBuilder =
|
||||
DeviceSecurityProfilesDelta.newBuilder().setHeader(header);
|
||||
|
||||
// Separately add all original dsps and new dsps into two maps. Key is content owner name,
|
||||
// value is a list of dsps created by this content owner.
|
||||
Map<String, List<SecurityProfile>> originalDspMap = initializeDspMap(originalDspList);
|
||||
Map<String, List<SecurityProfile>> newDspMap = initializeDspMap(newDspList);
|
||||
// Create a map to store DspDelta.Builder. Key is content owner name, value is dspDelta for each
|
||||
// owner.
|
||||
Map<String, DspDelta.Builder> dspDeltaBuilderMap = calculateDspDelta(originalDspMap, newDspMap);
|
||||
|
||||
// Export dspDeltaBuilderMap and return DeviceSecurityProfilesDelta proto.
|
||||
for (String owner : dspDeltaBuilderMap.keySet()) {
|
||||
DspDelta.Builder dspDeltaBuilder = dspDeltaBuilderMap.get(owner).setOwner(owner);
|
||||
deltaBuilder.addDspDelta(dspDeltaBuilder.build());
|
||||
}
|
||||
return deltaBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses {@link DeviceSecurityProfilesDelta} to obtain AddedList, RemovedList and ModifiedList
|
||||
* for all content owners from DeviceSecurityProfilesList.
|
||||
*/
|
||||
private void createDeviceSecurityProfilesDeltaInfo(DeviceSecurityProfilesDelta dspDelta) {
|
||||
for (DspDelta dspDeltaEntry : dspDelta.getDspDeltaList()) {
|
||||
dspAddedList.addAll(dspDeltaEntry.getAddedList());
|
||||
dspRemovedList.addAll(dspDeltaEntry.getRemovedList());
|
||||
dspModifiedList.addAll(dspDeltaEntry.getModifiedList());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates dsp map storing dsp list.
|
||||
*
|
||||
* @param dspList dsp list in DeviceSecurityProfileList proto.
|
||||
* @return a map which stores dsp list. Key is content owner name, value is a list of dsps for
|
||||
* that owner.
|
||||
*/
|
||||
private static Map<String, List<SecurityProfile>> initializeDspMap(
|
||||
DeviceSecurityProfileList dspList) {
|
||||
Map<String, List<SecurityProfile>> dspMap = new LinkedHashMap<>();
|
||||
for (SecurityProfile dsp : dspList.getDeviceSecurityProfilesList()) {
|
||||
dspMap.putIfAbsent(dsp.getOwner(), new ArrayList<>());
|
||||
dspMap.get(dsp.getOwner()).add(dsp);
|
||||
}
|
||||
return dspMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates dsp delta based on the original dsp and new dsp map.
|
||||
*
|
||||
* @param originalDspMap original dsp map.
|
||||
* @param newDspMap new dsp map.
|
||||
* @return a dsp delta map. Key is content owner name, value is the dsp delta builder belongs to
|
||||
* that owner.
|
||||
*/
|
||||
private static Map<String, DspDelta.Builder> calculateDspDelta(
|
||||
Map<String, List<SecurityProfile>> originalDspMap,
|
||||
Map<String, List<SecurityProfile>> newDspMap) {
|
||||
Map<String, DspDelta.Builder> dspDeltaBuilderMap = new LinkedHashMap<>();
|
||||
for (String owner : newDspMap.keySet()) {
|
||||
// Record already-processed original dsp set.
|
||||
Set<SecurityProfile> processedOriginalDspSet = new HashSet<>();
|
||||
|
||||
// If current owner is not shown in the original dsp map, add all new dsps to Add field for
|
||||
// this content owner and then continue checking the next owner from new dsp map.
|
||||
if (!originalDspMap.containsKey(owner)) {
|
||||
dspDeltaBuilderMap.putIfAbsent(owner, DspDelta.newBuilder().setOwner(owner));
|
||||
dspDeltaBuilderMap.get(owner).addAllAdded(newDspMap.get(owner));
|
||||
continue;
|
||||
}
|
||||
for (SecurityProfile newDsp : newDspMap.get(owner)) {
|
||||
// For each new dsp, compare with the original dsp list.
|
||||
// If two dsps are identical, record it to the already-processed list. And pass to the next
|
||||
// new dsp.
|
||||
if (originalDspMap.get(owner).contains(newDsp)) {
|
||||
// Record the original dsp which is dentical to new dsp in the already_processed list.
|
||||
processedOriginalDspSet.add(newDsp);
|
||||
continue;
|
||||
} else {
|
||||
// If new dsp can't find the equivalent dsp in the original list, need to figure out it is
|
||||
// an new added one or a modified one -modified one comes with the same dsp unique key
|
||||
// {dspName, owner, provider, startTime}.
|
||||
boolean sameDspUniqueKeyFound = false;
|
||||
for (SecurityProfile originalDsp : originalDspMap.get(owner)) {
|
||||
// Owner and provider are identical. Only need to compare dspName and startTime.
|
||||
if (originalDsp.getName().equals(newDsp.getName())
|
||||
&& (originalDsp.getControlTime().getStartTimeSeconds()
|
||||
== newDsp.getControlTime().getStartTimeSeconds())) {
|
||||
// Add original and new dsp to Modified field for this content owner.
|
||||
dspDeltaBuilderMap.putIfAbsent(owner, DspDelta.newBuilder().setOwner(owner));
|
||||
dspDeltaBuilderMap
|
||||
.get(owner)
|
||||
.addModifiedBuilder()
|
||||
.setPrevDsp(originalDsp)
|
||||
.setNewDsp(newDsp);
|
||||
// Record the original dsp in the already_processed list.
|
||||
processedOriginalDspSet.add(originalDsp);
|
||||
sameDspUniqueKeyFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sameDspUniqueKeyFound) {
|
||||
// Add new dsp to Added field for this content owner.
|
||||
dspDeltaBuilderMap.putIfAbsent(owner, DspDelta.newBuilder().setOwner(owner));
|
||||
dspDeltaBuilderMap.get(owner).addAdded(newDsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove already-processed dsps from originalDspMap for this content owner.
|
||||
originalDspMap.get(owner).removeAll(processedOriginalDspSet);
|
||||
}
|
||||
|
||||
// Add all remaining dsps from originalDspMap to Removed field.
|
||||
for (String owner : originalDspMap.keySet()) {
|
||||
if (!originalDspMap.get(owner).isEmpty()) {
|
||||
dspDeltaBuilderMap.putIfAbsent(owner, DspDelta.newBuilder().setOwner(owner));
|
||||
dspDeltaBuilderMap.get(owner).addAllRemoved(originalDspMap.get(owner));
|
||||
}
|
||||
}
|
||||
|
||||
return dspDeltaBuilderMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.SignedDeviceSecurityProfiles;
|
||||
import com.google.protobuf.ExtensionRegistry;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfileListProtos.DeviceSecurityProfileList;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta;
|
||||
import com.google.video.widevine.protos.SecurityProfileProtos.SecurityProfile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Device Security Profiles Wrapper class to parse and discover retrieved DSPs. */
|
||||
final class DeviceSecurityProfilesWrapper {
|
||||
private SignedDeviceSecurityProfiles signedDspList = null;
|
||||
private DeviceSecurityProfileList dspList = null;
|
||||
private final Map<String, List<SecurityProfile>> dspMap = new LinkedHashMap<>();
|
||||
private Set<String> ownerSet = null;
|
||||
|
||||
/**
|
||||
* Constructor to create DeviceSecurityProfilesWrapper object with {@link
|
||||
* SignedDeviceSecurityProfiles} as input.
|
||||
*
|
||||
* @param signedDspList SignedDeviceSecurityProfiles proto.
|
||||
*/
|
||||
public DeviceSecurityProfilesWrapper(SignedDeviceSecurityProfiles signedDspList)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(signedDspList, "'signedDspList' must not be null");
|
||||
this.signedDspList = signedDspList;
|
||||
parseDeviceSecurityProfilesList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to create DeviceSecurityProfilesWrapper object with byte array from {@link
|
||||
* SignedDeviceSecurityProfiles} serialized proto.
|
||||
*
|
||||
* @param signedDspListInfo a serialized SignedDeviceSecurityProfiles proto.
|
||||
*/
|
||||
public DeviceSecurityProfilesWrapper(byte[] signedDspListInfo)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(signedDspListInfo, "'signedDspListInfo' must not be null");
|
||||
signedDspList =
|
||||
SignedDeviceSecurityProfiles.parseFrom(
|
||||
signedDspListInfo, ExtensionRegistry.getEmptyRegistry());
|
||||
parseDeviceSecurityProfilesList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DeviceSecurityProfileList.
|
||||
*
|
||||
* @return DeviceSecurityProfileList a deserialized DeviceSecurityProfiles message from
|
||||
* SignedDeviceSecurityProfiles.
|
||||
*/
|
||||
public DeviceSecurityProfileList getDeviceSecurityProfileList() {
|
||||
return dspList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of DSPs shown in DeviceSecurityProfileList.
|
||||
*
|
||||
* @return int Number of DSPs shown in DeviceSecurityProfileList.
|
||||
*/
|
||||
public int getSize() {
|
||||
return dspList.getDeviceSecurityProfilesCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of DeviceSecurityProfiles for specific content owner.
|
||||
*
|
||||
* @param owner content owner name in String.
|
||||
* @return {@link List<SecurityProfile>} a list of DSPs for specific content owner. Return null if
|
||||
* none of the DSPs belongs to the specific content owner.
|
||||
*/
|
||||
public List<SecurityProfile> getDeviceSecurityProfiles(String owner) {
|
||||
if (isNullOrEmpty(owner)) {
|
||||
return null;
|
||||
}
|
||||
return dspMap.get(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content owner list from the DSPs.
|
||||
*
|
||||
* @return {@link List<String>} a list of content owners shown in the DSPs. Return null if owner
|
||||
* set is null or empty.
|
||||
*/
|
||||
public List<String> getOwners() {
|
||||
if (ownerSet == null || ownerSet.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayList<>(ownerSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one DeviceSecurityProfile given content owner and profile name.
|
||||
*
|
||||
* @param owner content owner name in String.
|
||||
* @param profileName dsp name in String.
|
||||
* @return {@link SecurityProfile) One specific DSP which matches content owner and profile name.
|
||||
* Return null if such DSP couldn't be found.
|
||||
*/
|
||||
SecurityProfile getDeviceSecurityProfile(String owner, String profileName) {
|
||||
List<SecurityProfile> list = dspMap.get(owner);
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
for (SecurityProfile securityProfile : list) {
|
||||
if (securityProfile.getName().equals(profileName)) {
|
||||
return securityProfile;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link DeviceSecurityProfilesDelta} of new signedDspList with current signedDspList.
|
||||
*
|
||||
* @param newSignedDspList new signed dsp list in SignedDeviceSecurityProfiles proto.
|
||||
* @return {@link DeviceSecurityProfilesDelta}.
|
||||
* @throws InvalidProtocolBufferException if failed to parse DeviceSecurityProfileList from
|
||||
* SignedDeviceSecurityProfiles.
|
||||
*/
|
||||
public DeviceSecurityProfilesDelta getDeviceSecurityProfilesDelta(
|
||||
SignedDeviceSecurityProfiles newSignedDspList) throws InvalidProtocolBufferException {
|
||||
checkNotNull(newSignedDspList, "'newSignedDspList' must not be null");
|
||||
DeviceSecurityProfilesDeltaWrapper dspDeltaWrapper =
|
||||
new DeviceSecurityProfilesDeltaWrapper(this.signedDspList, newSignedDspList);
|
||||
return dspDeltaWrapper.getDelta();
|
||||
}
|
||||
|
||||
private void parseDeviceSecurityProfilesList() throws InvalidProtocolBufferException {
|
||||
dspList =
|
||||
DeviceSecurityProfileList.parseFrom(
|
||||
signedDspList.getDeviceSecurityProfiles(), ExtensionRegistry.getEmptyRegistry());
|
||||
|
||||
// Add all DSPs into a map where key is dsp owner, value is a list of DSPs.
|
||||
for (SecurityProfile dsp : dspList.getDeviceSecurityProfilesList()) {
|
||||
dspMap.putIfAbsent(dsp.getOwner(), new ArrayList<>());
|
||||
dspMap.get(dsp.getOwner()).add(dsp);
|
||||
}
|
||||
// Get owner set from key set of dspMap.
|
||||
ownerSet = dspMap.keySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
package com.google.video.widevine.jts.tools;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices;
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.SignedDeviceSecurityProfiles;
|
||||
import com.google.chrome.widevine.frauddetection.v1eap1.FraudLevel;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.video.widevine.jts.providers.PublishedDevicesProvider;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLEnvironment;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatus;
|
||||
import com.google.video.widevine.sdk.wvpl.WvPLStatusException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Published Devices Client command line tool.
|
||||
*
|
||||
* <p>Provides a command line interface to get the latest {@code PublishedDevices} and {@code
|
||||
* SignedDeviceSecurityProfiles} data from the Widevine Published Devices Service.
|
||||
*
|
||||
* <p>Default Widevine Service API path: widevine.googleapis.com.
|
||||
*
|
||||
* <p>To build: bazel build
|
||||
* java/com/google/video/widevine/jts/tools:published_devices_cli_deploy.jar
|
||||
*
|
||||
* <p>To run: java -Djava.library.path=./path/to/license/sdk.so \ -jar
|
||||
* /path/to/published_devices_cli_deploy.jar \ -data_type PUBLISHED_DEVICESOrDSPInString \
|
||||
* -service_cert_path /path/to/cert_file.der \ -service_private_key_path /path/to/private_key.der \
|
||||
* -service_private_key_passphrase theprivatekeypassphrase \ -service_account_path
|
||||
* /path/to/service-account.json \ -provider_name providerNameInString
|
||||
*/
|
||||
public final class PublishedDevicesCli {
|
||||
private static final String PUBLISHED_DEVICES = "PUBLISHED_DEVICES";
|
||||
private static final String DSP = "DSP";
|
||||
private static final String IDRL = "IDRL";
|
||||
private static final String FRAUD_REPORT = "FRAUD_REPORT";
|
||||
private static final ImmutableList<String> DATA_TYPE_LIST =
|
||||
ImmutableList.of(PUBLISHED_DEVICES, DSP, IDRL, FRAUD_REPORT);
|
||||
|
||||
private static final String FRAUD_LEVEL_CRITICAL = "CRITICAL";
|
||||
private static final String FRAUD_LEVEL_NONE = "NONE";
|
||||
private static final ImmutableList<String> FRAUD_LEVEL_LIST =
|
||||
ImmutableList.of(FRAUD_LEVEL_CRITICAL, FRAUD_LEVEL_NONE);
|
||||
|
||||
private WvPLEnvironment environment = null;
|
||||
private PublishedDevicesProvider publishedDevices = null;
|
||||
private String serviceCertPath = null;
|
||||
private String privateKeyPath = null;
|
||||
private String privateKeyPassphrase = null;
|
||||
|
||||
/** Command Line Flags. */
|
||||
static class Flags {
|
||||
private Flags() {}
|
||||
|
||||
@Parameter(
|
||||
names = {"-h", "-help"},
|
||||
help = true)
|
||||
private boolean help = false;
|
||||
|
||||
@Parameter(
|
||||
names = "-data_type",
|
||||
description =
|
||||
"Set retrieved data type. Must be \"PUBLISHED_DEVICES\", \"DSP\", \"IDRL\" or"
|
||||
+ "\"FRAUD_REPORT\".")
|
||||
private String dataType = "PUBLISHED_DEVICES";
|
||||
|
||||
@Parameter(names = "-service_cert_path", description = "Path to service certificate")
|
||||
private String serviceCertPath = "";
|
||||
|
||||
@Parameter(
|
||||
names = "-service_private_key_path",
|
||||
description = "Path to private key file needed to decrypt service certificate")
|
||||
private String servicePrivateKeyPath = "";
|
||||
|
||||
@Parameter(
|
||||
names = "-service_private_key_passphrase",
|
||||
description = "Passphrase needed to decrypt the private key")
|
||||
private String servicePrivateKeyPassphrase = "";
|
||||
|
||||
@Parameter(
|
||||
names = "-service_account_path",
|
||||
description = "Path to a GCP Service Account json file. Required.")
|
||||
private String serviceAccountPath = "";
|
||||
|
||||
@Parameter(
|
||||
names = "-api_service_path",
|
||||
description = "Optional. Path to a Widevine API service.")
|
||||
private String apiServicePath = "widevine.googleapis.com";
|
||||
|
||||
@Parameter(
|
||||
names = "-provider_name",
|
||||
description =
|
||||
"Set provider name. Must provide when obtaining DSP and IDRL. Optional for obtaining"
|
||||
+ " PUBLISHED_DEVICES.")
|
||||
private String provider = "";
|
||||
|
||||
@Parameter(
|
||||
names = "-include_impact_analysis",
|
||||
description =
|
||||
"Option specifying whether or not to include impact analysis results in response.")
|
||||
private boolean includeImpactAnalysis = false;
|
||||
|
||||
@Parameter(
|
||||
names = "-last_dcsl_epoch_time_seconds",
|
||||
description =
|
||||
"Option that helps to calculate the DCSL impact analysis from a DCSL snapshot at"
|
||||
+ " last_dcsl_epoch_time to the latest DCSL snapshot. Time is contained in the last"
|
||||
+ " fetched DCSL DeviceCertificateStatusList.creation_time_seconds. Maximum"
|
||||
+ " timeframe is 30 days.")
|
||||
private Integer lastDcslEpochTimeSeconds = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-dcsl_type",
|
||||
description =
|
||||
"Option specifying which DCSL type needs to be returned in response. Valid options are"
|
||||
+ " Alpha, Beta or Released. Alpha is unverified DCSL which is not a release"
|
||||
+ " candidate yet. Beta is partially verified release candidate. Released is fully"
|
||||
+ " verified and is a release candidate available for production. By default, a"
|
||||
+ " released DCSL is returned in response.")
|
||||
private String dcslType = null;
|
||||
|
||||
@Parameter(names = "-s", description = "Save retrieved file path.")
|
||||
private String saveFilePath = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-fraud_license_request",
|
||||
description =
|
||||
"Base64 encoded fraud license request from the device. Required for fraud reporting.")
|
||||
private String fraudLicenseRequest = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-fraud_clear_id",
|
||||
description =
|
||||
"Base64 encoded clear client id. Required if the one in license request is encrypted.")
|
||||
private String fraudClearId = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-fraud_user_agent",
|
||||
description = "User agent of the fraud license request. Optional.")
|
||||
private String fraudUserAgent = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-fraud_reason",
|
||||
description = "Reason the device is considered fraudulent. Optional.")
|
||||
private String fraudReason = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-fraud_level",
|
||||
description =
|
||||
"Level of fraud, must be one of \"CRITICAL\" or \"NONE\". A \"NONE\" fraud level is"
|
||||
+ " used to \"unrevoke\" a device, meaning the device is not fraudulent. Optional.")
|
||||
private String fraudLevel = "CRITICAL";
|
||||
}
|
||||
|
||||
public PublishedDevicesCli(
|
||||
String dataType,
|
||||
String serviceCertPath,
|
||||
String privateKeyPath,
|
||||
String privateKeyPassphrase,
|
||||
String serviceAccountPath,
|
||||
String apiServicePath,
|
||||
String provider,
|
||||
boolean includeImpactAnalysis,
|
||||
Integer lastDcslEpochTimeSeconds,
|
||||
String dcslType)
|
||||
throws Exception {
|
||||
this.serviceCertPath = serviceCertPath;
|
||||
this.privateKeyPath = privateKeyPath;
|
||||
this.privateKeyPassphrase = privateKeyPassphrase;
|
||||
// Construct PublishedDevicesProvider to obtain PUBLISHED_DEVICES or DSPs.
|
||||
if (dataType.equals(PUBLISHED_DEVICES)) {
|
||||
initializeWvplEnvironment();
|
||||
}
|
||||
publishedDevices =
|
||||
new PublishedDevicesProvider(
|
||||
environment,
|
||||
serviceAccountPath,
|
||||
apiServicePath,
|
||||
provider,
|
||||
includeImpactAnalysis,
|
||||
lastDcslEpochTimeSeconds,
|
||||
dcslType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest {@code PublishedDevices} from the Widevine Published Devices Service.
|
||||
*
|
||||
* @return The latest PublishedDevices data.
|
||||
* @throws InterruptedException upon RPC failure.
|
||||
* @throws WvPLStatusException upon WvPLBaseEnvironment errors.
|
||||
*/
|
||||
public PublishedDevices getPublishedDevices() throws InterruptedException, WvPLStatusException {
|
||||
return publishedDevices.getPublishedDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest {@code SignedDeviceSecurityProfiles} from the Widevine Published Devices
|
||||
* Service.
|
||||
*
|
||||
* @return The latest SignedDeviceSecurityProfiles data.
|
||||
*/
|
||||
public SignedDeviceSecurityProfiles getSignedDeviceSecurityProfiles()
|
||||
throws InterruptedException, WvPLStatusException {
|
||||
return publishedDevices.getSignedDeviceSecurityProfiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest Individual Device Revocation List from the Widevine Published Devices Service.
|
||||
*
|
||||
* @return The latest SignedDeviceSecurityProfiles data.
|
||||
*/
|
||||
public byte[] getIndividualDeviceRevocationList() throws InterruptedException {
|
||||
return publishedDevices.getIndividualDeviceRevocationList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a fraudulent device to Widevine.
|
||||
*
|
||||
* @param licenseRequest Base64 encoded fraud license request from the device. Required.
|
||||
* @param clearClientId Base64 encoded clear client id. Required if the one in license request is
|
||||
* encrypted.
|
||||
* @param userAgent User agent of the fraud license request. Optional.
|
||||
* @param reason Reason the device is considered fraudulent. Optional.
|
||||
* @param fraudScore Fraud score of the device. Required.
|
||||
* @return The response message from Widevine server.
|
||||
*/
|
||||
public byte[] reportFraudulentDevice(
|
||||
String licenseRequest,
|
||||
String clearClientId,
|
||||
String userAgent,
|
||||
String reason,
|
||||
FraudLevel.FraudScore fraudScore)
|
||||
throws InterruptedException, IOException {
|
||||
return publishedDevices.reportFraudulentDevice(
|
||||
licenseRequest, clearClientId, userAgent, reason, fraudScore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves byte array to a file.
|
||||
*
|
||||
* @param saveFilePath The path to the save file.
|
||||
* @param byteArray a byte array transformed from proto.
|
||||
*/
|
||||
public static void saveByteArrayToFile(String saveFilePath, byte[] byteArray) throws IOException {
|
||||
Files.write(Path.of(saveFilePath), BaseEncoding.base64Url().encode(byteArray).getBytes(UTF_8));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Flags flags = new Flags();
|
||||
JCommander jCommander = new JCommander(flags);
|
||||
jCommander.parse(args);
|
||||
if (flags.help) {
|
||||
jCommander.usage();
|
||||
return;
|
||||
}
|
||||
// Check flags.
|
||||
if (!DATA_TYPE_LIST.contains(flags.dataType)) {
|
||||
System.out.println("Data type should be selected from:" + DATA_TYPE_LIST);
|
||||
System.err.println("Error selecting data type. Exit");
|
||||
System.exit(-1);
|
||||
}
|
||||
if (flags.provider.isEmpty() && !flags.dataType.equals(PUBLISHED_DEVICES)) {
|
||||
System.err.println("Failed to provide the provider name. Exit");
|
||||
System.exit(-1);
|
||||
}
|
||||
if (flags.serviceAccountPath.isEmpty()) {
|
||||
System.err.println("service_account_path is required. Exit");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
PublishedDevicesCli devices =
|
||||
new PublishedDevicesCli(
|
||||
flags.dataType,
|
||||
flags.serviceCertPath,
|
||||
flags.servicePrivateKeyPath,
|
||||
flags.servicePrivateKeyPassphrase,
|
||||
flags.serviceAccountPath,
|
||||
flags.apiServicePath,
|
||||
flags.provider,
|
||||
flags.includeImpactAnalysis,
|
||||
flags.lastDcslEpochTimeSeconds,
|
||||
flags.dcslType);
|
||||
|
||||
byte[] content = null;
|
||||
if (flags.dataType.equals(PUBLISHED_DEVICES)) {
|
||||
content = devices.getPublishedDevices().toByteArray();
|
||||
} else if (flags.dataType.equals(DSP)) {
|
||||
content = devices.getSignedDeviceSecurityProfiles().toByteArray();
|
||||
} else if (flags.dataType.equals(IDRL)) {
|
||||
content = devices.getIndividualDeviceRevocationList();
|
||||
} else if (flags.dataType.equals(FRAUD_REPORT)) {
|
||||
content =
|
||||
devices.reportFraudulentDevice(
|
||||
flags.fraudLicenseRequest,
|
||||
flags.fraudClearId,
|
||||
flags.fraudUserAgent,
|
||||
flags.fraudReason,
|
||||
getFraudScore(flags.fraudLevel));
|
||||
}
|
||||
if (flags.saveFilePath != null) {
|
||||
saveByteArrayToFile(flags.saveFilePath, content);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeWvplEnvironment() throws Exception {
|
||||
environment = new WvPLEnvironment(new HashMap<>());
|
||||
// Set service certificate.
|
||||
WvPLStatus status =
|
||||
environment.setServiceCertificate(
|
||||
loadDataFromFile(serviceCertPath),
|
||||
loadDataFromFile(privateKeyPath),
|
||||
privateKeyPassphrase.getBytes(UTF_8));
|
||||
if (!status.getStatusCode().equals(WvPLStatus.StatusCode.OK)) {
|
||||
throw new Exception("Set server certificate status: " + status);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] loadDataFromFile(String filePath) throws IOException {
|
||||
return Files.readAllBytes(Path.of(filePath));
|
||||
}
|
||||
|
||||
public static FraudLevel.FraudScore getFraudScore(String fraudLevel) {
|
||||
switch (fraudLevel) {
|
||||
case FRAUD_LEVEL_CRITICAL:
|
||||
return FraudLevel.FraudScore.FRAUD_SCORE_CRITICAL;
|
||||
case FRAUD_LEVEL_NONE:
|
||||
return FraudLevel.FraudScore.FRAUD_SCORE_NONE;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Fraud level should be selected from: "
|
||||
+ FRAUD_LEVEL_LIST
|
||||
+ ". Invalid fraud level: "
|
||||
+ fraudLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
package com.google.video.widevine.jts.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices;
|
||||
import com.google.protobuf.ExtensionRegistry;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatus;
|
||||
import com.google.video.widevine.protos.DeviceCertificateStatusProtos.PublishedDevicesList;
|
||||
import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta;
|
||||
import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta.Header;
|
||||
import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta.Modified;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Published Devices Delta Wrapper class to get {@link PublishedDevicesDelta}. */
|
||||
public final class PublishedDevicesDeltaWrapper {
|
||||
private PublishedDevicesList originalList = null;
|
||||
private PublishedDevicesList newList = null;
|
||||
private PublishedDevicesDelta publishedDevicesDelta = null;
|
||||
private final Map<Integer, DeviceCertificateStatus> dcslAddedMap = new LinkedHashMap<>();
|
||||
private final Map<Integer, DeviceCertificateStatus> dcslRemovedMap = new LinkedHashMap<>();
|
||||
private final Map<Integer, Modified> dcslModifiedMap = new LinkedHashMap<>();
|
||||
static final int MAJOR_VERSION = 1;
|
||||
static final int MINOR_VERSION = 1;
|
||||
static final int RELEASE = 0;
|
||||
|
||||
/**
|
||||
* PublishedDevicesDeltaWrapper constructor. The input is two byte array serialized
|
||||
* PublishedDevices proto.
|
||||
*
|
||||
* @param publishedDevicesInBytes1 first serialized PublishedDevices proto in bytes.
|
||||
* @param publishedDevicesInBytes2 second serialized PublishedDevices proto in bytes.
|
||||
* @throws InvalidProtocolBufferException if failed to parse published devices or if failed to
|
||||
* parse PublishedDevicesList.
|
||||
*/
|
||||
public PublishedDevicesDeltaWrapper(
|
||||
byte[] publishedDevicesInBytes1, byte[] publishedDevicesInBytes2)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(publishedDevicesInBytes1, "'publishedDevicesInBytes1' must not be null");
|
||||
checkNotNull(publishedDevicesInBytes2, "'publishedDevicesInBytes2' must not be null");
|
||||
PublishedDevices publishedDevices1 =
|
||||
PublishedDevices.parseFrom(publishedDevicesInBytes1, ExtensionRegistry.getEmptyRegistry());
|
||||
PublishedDevices publishedDevices2 =
|
||||
PublishedDevices.parseFrom(publishedDevicesInBytes2, ExtensionRegistry.getEmptyRegistry());
|
||||
parsePublishedDevicesList(publishedDevices1, publishedDevices2);
|
||||
this.publishedDevicesDelta = createPublishedDevicesDelta(originalList, newList);
|
||||
createPublishedDevicesDeltaInfo(publishedDevicesDelta);
|
||||
}
|
||||
|
||||
/**
|
||||
* PublishedDevicesDeltaWrapper constructor. The input is two PublishedDevices protos.
|
||||
*
|
||||
* @param publishedDevices1 first PublishedDevices proto.
|
||||
* @param publishedDevices2 second PublishedDevices proto.
|
||||
* @throws InvalidProtocolBufferException if failed to parse PublishedDevicesList from published
|
||||
* devices.
|
||||
*/
|
||||
public PublishedDevicesDeltaWrapper(
|
||||
PublishedDevices publishedDevices1, PublishedDevices publishedDevices2)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(publishedDevices1, "'publishedDevices1' must not be null");
|
||||
checkNotNull(publishedDevices2, "'publishedDevices2' must not be null");
|
||||
parsePublishedDevicesList(publishedDevices1, publishedDevices2);
|
||||
this.publishedDevicesDelta = createPublishedDevicesDelta(originalList, newList);
|
||||
createPublishedDevicesDeltaInfo(publishedDevicesDelta);
|
||||
}
|
||||
|
||||
/**
|
||||
* PublishedDevicesDeltaWrapper constructor. The input is PublishedDevicesDelta proto.
|
||||
*
|
||||
* @param publishedDevicesDelta PublishedDevicesDeltaWrapper proto.
|
||||
*/
|
||||
public PublishedDevicesDeltaWrapper(PublishedDevicesDelta publishedDevicesDelta) {
|
||||
checkNotNull(publishedDevicesDelta, "'delta' must not be null");
|
||||
this.publishedDevicesDelta = publishedDevicesDelta;
|
||||
createPublishedDevicesDeltaInfo(publishedDevicesDelta);
|
||||
}
|
||||
|
||||
/** Returns {@link PublishedDevicesDelta} of originalPublishedDevices and newPublishedDevices. */
|
||||
public PublishedDevicesDelta getDelta() {
|
||||
return publishedDevicesDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link PublishedDevicesDelta} of originalPublishedDevices and newPublishedDevices.
|
||||
*
|
||||
* @param originalList original list in PublishedDevicesList proto
|
||||
* @param newList new list in PublishedDevicesList proto
|
||||
*/
|
||||
static PublishedDevicesDelta createPublishedDevicesDelta(
|
||||
PublishedDevicesList originalList, PublishedDevicesList newList) {
|
||||
// Construct PublishedDevicesDelta.
|
||||
PublishedDevicesDelta.Builder deltaBuilder = PublishedDevicesDelta.newBuilder();
|
||||
// Construct Header object.
|
||||
Header header =
|
||||
Header.newBuilder()
|
||||
.setPrevCreationTimeSeconds(originalList.getCreationTimeSeconds())
|
||||
.setNewCreationTimeSeconds(newList.getCreationTimeSeconds())
|
||||
.build();
|
||||
deltaBuilder.setHeader(header);
|
||||
|
||||
// Add removed, added and modified field in to delta.
|
||||
List<DeviceCertificateStatus> prevDCSL = originalList.getDeviceCertificateStatusList();
|
||||
List<DeviceCertificateStatus> newDcsl = newList.getDeviceCertificateStatusList();
|
||||
Map<Integer, DeviceCertificateStatus> dcslMap = new LinkedHashMap<>();
|
||||
// Add all the original DCSLs into the map.
|
||||
for (DeviceCertificateStatus dcsl : prevDCSL) {
|
||||
dcslMap.put(dcsl.getDeviceInfo().getSystemId(), dcsl);
|
||||
}
|
||||
|
||||
for (DeviceCertificateStatus dcsl : newDcsl) {
|
||||
int systemId = dcsl.getDeviceInfo().getSystemId();
|
||||
if (dcslMap.containsKey(systemId) && !dcsl.equals(dcslMap.get(systemId))) {
|
||||
deltaBuilder.addModifiedBuilder().setPrevDevice(dcslMap.get(systemId)).setNewDevice(dcsl);
|
||||
} else if (!dcslMap.containsKey(systemId)) {
|
||||
// Add the new DCSL into added field in PublishedDevicesDeltaWrapper.
|
||||
deltaBuilder.addAdded(dcsl);
|
||||
}
|
||||
// Remove the iterated DCSL from the map.
|
||||
dcslMap.remove(systemId);
|
||||
}
|
||||
// Add the original DCSL into removed field in PublishedDevicesDeltaWrapper.
|
||||
if (!dcslMap.isEmpty()) {
|
||||
deltaBuilder.addAllRemoved(dcslMap.values());
|
||||
}
|
||||
|
||||
return deltaBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted text output of the {@link PublishedDevicesDelta}.
|
||||
*
|
||||
* @return String String format of publishedDevices.
|
||||
*/
|
||||
public static String toString(PublishedDevicesDelta delta) {
|
||||
return delta.toString();
|
||||
}
|
||||
|
||||
/** Parse {@link PublishedDevicesList} from {@link PublishedDevices}. */
|
||||
private void parsePublishedDevicesList(
|
||||
PublishedDevices publishedDevices1, PublishedDevices publishedDevices2)
|
||||
throws InvalidProtocolBufferException {
|
||||
// Parse PublishedDevicesList proto.
|
||||
originalList =
|
||||
PublishedDevicesList.parseFrom(
|
||||
publishedDevices1.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry());
|
||||
newList =
|
||||
PublishedDevicesList.parseFrom(
|
||||
publishedDevices2.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry());
|
||||
|
||||
// Swap the PublishedDevicesList list if originalList is newer than newList.
|
||||
if (originalList.getCreationTimeSeconds() > newList.getCreationTimeSeconds()) {
|
||||
PublishedDevicesList temp = newList;
|
||||
newList = originalList;
|
||||
originalList = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link DeviceCertificateStatus} of the specific system_id.
|
||||
*
|
||||
* @param systemId Device system_id.
|
||||
* @return DeviceCertificateStatus Returns DeviceCertificateStatus of the specific system_id if it
|
||||
* is added. Otherwise it will return null.
|
||||
*/
|
||||
public DeviceCertificateStatus getAddedDeviceCertificateStatus(int systemId) {
|
||||
return dcslAddedMap.get(systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link DeviceCertificateStatus} of the specific system_id.
|
||||
*
|
||||
* @param systemId Device system_id.
|
||||
* @return DeviceCertificateStatus Returns the DeviceCertificateStatus of the specific system_id
|
||||
* if it is removed.Otherwise it will return null.
|
||||
*/
|
||||
public DeviceCertificateStatus getRemovedDeviceCertificateStatus(int systemId) {
|
||||
return dcslRemovedMap.get(systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link Modified} of the specific system_id. Return null if not found.
|
||||
*
|
||||
* @param systemId Device system_id.
|
||||
* @return Modified Returns ModifiedDeviceCertificateStatus of the specific system_id. Return null
|
||||
* if not found.
|
||||
*/
|
||||
public Modified getModifiedDeviceCertificateStatus(int systemId) {
|
||||
return dcslModifiedMap.get(systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of added DeviceCertificateStatus in delta.
|
||||
*
|
||||
* @return a list of system_ids for added DeviceCertificateStatus in delta.
|
||||
*/
|
||||
public List<Integer> getAddedDevices() {
|
||||
return new ArrayList<>(dcslAddedMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of modified DeviceCertificateStatus in delta.
|
||||
*
|
||||
* @return a list of system_ids for modified DeviceCertificateStatus in delta.
|
||||
*/
|
||||
public List<Integer> getModifiedDevices() {
|
||||
return new ArrayList<>(dcslModifiedMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of system ids for removed DeviceCertificateStatus in delta.
|
||||
*
|
||||
* @return a list of system_ids for removed DeviceCertificateStatus in delta.
|
||||
*/
|
||||
public List<Integer> getRemovedDevices() {
|
||||
return new ArrayList<>(dcslRemovedMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of Published Devices Release.
|
||||
*
|
||||
* @return the version of Published Devices Release as a String.
|
||||
*/
|
||||
public String getVersion() {
|
||||
return MAJOR_VERSION + "." + MINOR_VERSION + "." + RELEASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse PublishedDevicesDeltaWrapper to get AddedMap, RemovedMap and ModifiedMap for
|
||||
* PublishedDevicesList.
|
||||
*
|
||||
* @param publishedDevicesDelta PublishedDevicesDelta delta.
|
||||
*/
|
||||
private void createPublishedDevicesDeltaInfo(PublishedDevicesDelta publishedDevicesDelta) {
|
||||
for (DeviceCertificateStatus status : publishedDevicesDelta.getAddedList()) {
|
||||
dcslAddedMap.put(status.getDeviceInfo().getSystemId(), status);
|
||||
}
|
||||
for (DeviceCertificateStatus status : publishedDevicesDelta.getRemovedList()) {
|
||||
dcslRemovedMap.put(status.getDeviceInfo().getSystemId(), status);
|
||||
}
|
||||
for (Modified status : publishedDevicesDelta.getModifiedList()) {
|
||||
dcslModifiedMap.put(status.getPrevDevice().getDeviceInfo().getSystemId(), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.tools;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base64;
|
||||
import static com.google.common.io.BaseEncoding.base64Url;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatus;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta;
|
||||
import com.google.video.widevine.protos.DeviceSecurityProfilesDeltaProtos.DeviceSecurityProfilesDelta.DspDelta;
|
||||
import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta;
|
||||
import com.google.video.widevine.protos.SecurityProfileProtos.SecurityProfile;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Published Devices command line tool.
|
||||
*
|
||||
* <p>Provides a command line tool which could help to (1) get the diff between two PublishedDevices
|
||||
* Proto, parse the PublishedDevices and PublishedDevicesDelta. (2) get the diff between two
|
||||
* SignedDeviceSecurityProfiles Proto, parse the DeviceSecurityProfiles and
|
||||
* DeviceSecurityProfilesDelta.
|
||||
*
|
||||
* <p>To build: Bazel build tools:published_devices_delta_deploy.jar
|
||||
*
|
||||
* <p>Commands for PublishedDevices:
|
||||
*
|
||||
* <p>To run: java -jar /path/to/published_devices_lib_deploy.jar -new_file_path path
|
||||
* -original_file_path path -print
|
||||
*
|
||||
* <p>To run: java -jar /path/to/published_devices_lib_deploy.jar -new_file_path path
|
||||
* -original_file_path path -system_id 100 -get_system_ids
|
||||
*
|
||||
* <p>To run: java -jar /path/to/published_devices_lib_deploy.jar -query path -system_id 100
|
||||
*
|
||||
* <p>Commands for DeviceSecurityProfiles:
|
||||
*
|
||||
* <p>Get DSP delta, save and print it: java -jar /path/to/published_devices_lib_deploy.jar
|
||||
* -data_type DSP -new_file_path path -original_file_path path -print
|
||||
*
|
||||
* <p>Obtain the dsp delta per content owner: java -jar /path/to/published_devices_lib_deploy.jar
|
||||
* -data_type DSP -new_file_path path -original_file_path path -content_owner owner_name
|
||||
*
|
||||
* <p>Obtain Added/Removed/Modified list in dsp delta: java -jar
|
||||
* /path/to/published_devices_lib_deploy.jar -data_type DSP -new_file_path path -original_file_path
|
||||
* path -get_specific_field_in_dsp_delta field_name
|
||||
*
|
||||
* <p>Get DSPs for specific owner: java -jar /path/to/published_devices_lib_deploy.jar -data_type
|
||||
* DSP -query path -content_owner owner_name
|
||||
*
|
||||
* <p>Get owner list from one retrieved dsp list: java -jar
|
||||
* /path/to/published_devices_lib_deploy.jar -data_type DSP -query path -get_owners
|
||||
*
|
||||
* <p>Get targeted dsp given contentOwner and profile name: java -jar
|
||||
* /path/to/published_devices_lib_deploy.jar -data_type DSP -query path -content_owner owner_name
|
||||
* -profile_name profile_name
|
||||
*/
|
||||
public class PublishedDevicesMain {
|
||||
private static final Logger logger = Logger.getLogger(PublishedDevicesMain.class.getName());
|
||||
private static final int ZERO_SYSTEM_ID = 0;
|
||||
private static final String JSON_NAME = "signedList";
|
||||
private static final String PUBLISHED_DEVICES = "PUBLISHED_DEVICES";
|
||||
private static final String DSP = "DSP";
|
||||
private static final ImmutableList<String> DATA_TYPE_LIST =
|
||||
ImmutableList.of(PUBLISHED_DEVICES, DSP);
|
||||
private static final String ADDED_FIELD_IN_DSP_DELTA = "added";
|
||||
private static final String MODIFIED_FIELD_IN_DSP_DELTA = "modified";
|
||||
private static final String REMOVED_FIELD_IN_DSP_DELTA = "removed";
|
||||
|
||||
/** Command Line Flags. */
|
||||
static class Flags {
|
||||
private Flags() {}
|
||||
|
||||
// Shared parameters for both PublishedDevices and DSP.
|
||||
@Parameter(
|
||||
names = "-data_type",
|
||||
description = "Set parsed data type. Must be \"PUBLISHED_DEVICES\" or \"DSP\".")
|
||||
private String dataType = "PUBLISHED_DEVICES";
|
||||
|
||||
@Parameter(
|
||||
names = "-original_file_path",
|
||||
description =
|
||||
"Path to original file. Could be the original file for either PublishedDevices or"
|
||||
+ " DeviceSecurityProfiles.")
|
||||
private String originalFilePath = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-new_file_path",
|
||||
description =
|
||||
"Path to new file. Could be the new file for either PublishedDevices or"
|
||||
+ " DeviceSecurityProfiles.")
|
||||
private String newFilePath = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-print",
|
||||
description = "Setting to true, if content provider wants to print the delta in String.")
|
||||
private boolean print = false;
|
||||
|
||||
@Parameter(names = "-query", description = "Parse the input file.")
|
||||
private String query = null;
|
||||
|
||||
// Unique parameters for PublishedDevices.
|
||||
@Parameter(
|
||||
names = "-system_id",
|
||||
description = "Device system-id shown in PublishedDevicesList.")
|
||||
private int systemId = ZERO_SYSTEM_ID;
|
||||
|
||||
@Parameter(
|
||||
names = "-get_system_ids",
|
||||
description =
|
||||
"Boolean to get list of system_ids in added/removed/modified PublishedDevicesList.")
|
||||
private boolean getSystemIdsList = false;
|
||||
|
||||
// Unique parameters for DeviceSecurityProfiles.
|
||||
@Parameter(
|
||||
names = "-content_owner",
|
||||
description = "Content owner name to retrieve corresponding DeviceSecurityProfiles.")
|
||||
private String contentOwner = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-get_specific_field_in_dsp_delta",
|
||||
description =
|
||||
"Optional. Obtain one specific field (added, removed or modified) in dsp delta."
|
||||
+ " Returned list covers all content owners.")
|
||||
private String getSpecificFieldInDspDelta = null;
|
||||
|
||||
@Parameter(
|
||||
names = "-get_owners",
|
||||
description = "Obtain owner list from one DeviceSecurityProfilesList.")
|
||||
private boolean getOwners = false;
|
||||
|
||||
@Parameter(names = "-profile_name", description = "device security profile name.")
|
||||
private String profileName = null;
|
||||
}
|
||||
|
||||
/** Main function to run Published Devices Delta command line tool. */
|
||||
public static void main(String[] args) {
|
||||
Flags flags = new Flags();
|
||||
new JCommander(flags).parse(args);
|
||||
// Check the FLAGs.
|
||||
if (!DATA_TYPE_LIST.contains(flags.dataType)) {
|
||||
System.out.println("Data type should be selected from:" + DATA_TYPE_LIST);
|
||||
logger.log(Level.SEVERE, "Data type should match with PUBLISHED_DEVICES or DSP.");
|
||||
}
|
||||
|
||||
if (flags.dataType.equals(PUBLISHED_DEVICES)) {
|
||||
if (flags.newFilePath != null && flags.originalFilePath != null) {
|
||||
parsePublishedDevicesDelta(flags);
|
||||
} else if (flags.query != null) {
|
||||
queryPublishedDevices(flags);
|
||||
}
|
||||
} else if (flags.dataType.equals(DSP)) {
|
||||
if (flags.newFilePath != null && flags.originalFilePath != null) {
|
||||
parseDeviceSecurityProfilesDelta(flags);
|
||||
} else if (flags.query != null) {
|
||||
queryDeviceSecurityProfiles(flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse the argument related to PublishedDevicesDelta. */
|
||||
private static void parsePublishedDevicesDelta(Flags flags) {
|
||||
try {
|
||||
byte[] originalPublishedDevices =
|
||||
getPublishedDevicesOrDspFileAsBytes(flags.originalFilePath, flags.dataType);
|
||||
byte[] newPublishedDevices =
|
||||
getPublishedDevicesOrDspFileAsBytes(flags.newFilePath, flags.dataType);
|
||||
checkLoadFileResult(flags.originalFilePath, originalPublishedDevices);
|
||||
checkLoadFileResult(flags.newFilePath, newPublishedDevices);
|
||||
PublishedDevicesDeltaWrapper devices =
|
||||
new PublishedDevicesDeltaWrapper(originalPublishedDevices, newPublishedDevices);
|
||||
PublishedDevicesDelta delta = devices.getDelta();
|
||||
if (flags.print) {
|
||||
System.out.println(delta);
|
||||
}
|
||||
parseDeltaInfo(devices, flags);
|
||||
} catch (IOException e) {
|
||||
logger.log(
|
||||
Level.SEVERE, "IOException encountered trying to open published devices files: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse the argument related to DeviceSecurityProfilesDelta. */
|
||||
private static void parseDeviceSecurityProfilesDelta(Flags flags) {
|
||||
try {
|
||||
byte[] originalDeviceSecurityProfiles =
|
||||
getPublishedDevicesOrDspFileAsBytes(flags.originalFilePath, flags.dataType);
|
||||
byte[] newDeviceSecurityProfiles =
|
||||
getPublishedDevicesOrDspFileAsBytes(flags.newFilePath, flags.dataType);
|
||||
checkLoadFileResult(flags.originalFilePath, originalDeviceSecurityProfiles);
|
||||
checkLoadFileResult(flags.newFilePath, newDeviceSecurityProfiles);
|
||||
DeviceSecurityProfilesDeltaWrapper dspDeltaWrapper =
|
||||
new DeviceSecurityProfilesDeltaWrapper(
|
||||
originalDeviceSecurityProfiles, newDeviceSecurityProfiles);
|
||||
DeviceSecurityProfilesDelta delta = dspDeltaWrapper.getDelta();
|
||||
if (flags.print) {
|
||||
System.out.println(delta);
|
||||
}
|
||||
parseDeltaInfo(dspDeltaWrapper, flags);
|
||||
} catch (IOException e) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"IOException encountered trying to open device security profiles files: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse the detailed info shown in PublishedDevicesDelta. */
|
||||
private static void parseDeltaInfo(
|
||||
PublishedDevicesDeltaWrapper publishedDevicesDelta, Flags flags) {
|
||||
if (flags.systemId != 0) {
|
||||
if (publishedDevicesDelta.getAddedDeviceCertificateStatus(flags.systemId) != null) {
|
||||
System.out.println(
|
||||
flags.systemId + " system-id is found in added field of published devices delta.");
|
||||
System.out.println(publishedDevicesDelta.getAddedDeviceCertificateStatus(flags.systemId));
|
||||
|
||||
} else if (publishedDevicesDelta.getRemovedDeviceCertificateStatus(flags.systemId) != null) {
|
||||
System.out.println(
|
||||
flags.systemId + " system-id is found in removed field of published devices delta.");
|
||||
System.out.println(publishedDevicesDelta.getRemovedDeviceCertificateStatus(flags.systemId));
|
||||
} else if (publishedDevicesDelta.getModifiedDeviceCertificateStatus(flags.systemId) != null) {
|
||||
System.out.println(
|
||||
flags.systemId + " system-id is found in modified field of published devices delta.");
|
||||
System.out.println(
|
||||
publishedDevicesDelta.getModifiedDeviceCertificateStatus(flags.systemId));
|
||||
} else {
|
||||
logger.log(Level.SEVERE, flags.systemId + "was not found in the PublishedDevicesDelta.");
|
||||
}
|
||||
}
|
||||
if (flags.getSystemIdsList) {
|
||||
System.out.println(
|
||||
"List of system_id for added published devices in published devices delta: "
|
||||
+ publishedDevicesDelta.getAddedDevices());
|
||||
System.out.println(
|
||||
"List of system_id for removed published devices in published devices delta: "
|
||||
+ publishedDevicesDelta.getRemovedDevices());
|
||||
System.out.println(
|
||||
"List of system_id for removed published devices in published devices delta: "
|
||||
+ publishedDevicesDelta.getModifiedDevices());
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse the detailed info shown in DeviceSecurityProfilesDelta. */
|
||||
private static void parseDeltaInfo(
|
||||
DeviceSecurityProfilesDeltaWrapper dspDeltaWrapper, Flags flags) {
|
||||
if (flags.getSpecificFieldInDspDelta != null) {
|
||||
if (Ascii.toLowerCase(flags.getSpecificFieldInDspDelta).equals(ADDED_FIELD_IN_DSP_DELTA)) {
|
||||
System.out.println(
|
||||
"List of added DSPs in device security profiles delta: "
|
||||
+ dspDeltaWrapper.getAddedDeviceSecurityProfiles());
|
||||
} else if (Ascii.toLowerCase(flags.getSpecificFieldInDspDelta)
|
||||
.equals(MODIFIED_FIELD_IN_DSP_DELTA)) {
|
||||
System.out.println(
|
||||
"List of modified DSPs in device security profiles delta: "
|
||||
+ dspDeltaWrapper.getModifiedDeviceSecurityProfiles());
|
||||
} else if (Ascii.toLowerCase(flags.getSpecificFieldInDspDelta)
|
||||
.equals(REMOVED_FIELD_IN_DSP_DELTA)) {
|
||||
System.out.println(
|
||||
"List of removed DSPs in device security profiles delta: "
|
||||
+ dspDeltaWrapper.getRemovedDeviceSecurityProfiles());
|
||||
} else {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
flags.getSpecificFieldInDspDelta
|
||||
+ "is not a valid field in DeviceSecurityProfilesDelta.");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.contentOwner != null) {
|
||||
DspDelta dspDelta = dspDeltaWrapper.getDeviceSecurityProfilesDelta(flags.contentOwner);
|
||||
if (dspDelta != null) {
|
||||
System.out.println("Obtain the dsp delta for specific content owner: " + dspDelta);
|
||||
} else {
|
||||
logger.log(
|
||||
Level.WARNING, flags.contentOwner + "is not shown in DeviceSecurityProfilesDelta.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void queryPublishedDevices(Flags flags) {
|
||||
try {
|
||||
byte[] publishedDevices = getPublishedDevicesOrDspFileAsBytes(flags.query, flags.dataType);
|
||||
checkLoadFileResult(flags.query, publishedDevices);
|
||||
PublishedDevicesWrapper wrapper = new PublishedDevicesWrapper(publishedDevices);
|
||||
if (flags.systemId != ZERO_SYSTEM_ID) {
|
||||
DeviceCertificateStatus deviceCertificateStatus =
|
||||
wrapper.getDeviceCertificateStatus(flags.systemId);
|
||||
if (deviceCertificateStatus == null) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
flags.systemId
|
||||
+ " (system-id) was not found in PublishedDevicesList from "
|
||||
+ flags.query);
|
||||
System.exit(1);
|
||||
}
|
||||
System.out.println(deviceCertificateStatus);
|
||||
// TODO(b/160253740): Add ProvisonedStatus and ProvisionedDeviceInfo functions.
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"InvalidProtocolBufferException encountered to parse device certificate status list"
|
||||
+ " or published devices proto:"
|
||||
+ e);
|
||||
} catch (IOException e) {
|
||||
logger.log(
|
||||
Level.SEVERE, "IOException encountered trying to open published devices file: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void queryDeviceSecurityProfiles(Flags flags) {
|
||||
try {
|
||||
byte[] deviceSecurityProfiles =
|
||||
getPublishedDevicesOrDspFileAsBytes(flags.query, flags.dataType);
|
||||
checkLoadFileResult(flags.query, deviceSecurityProfiles);
|
||||
DeviceSecurityProfilesWrapper dspWrapper =
|
||||
new DeviceSecurityProfilesWrapper(deviceSecurityProfiles);
|
||||
if (flags.contentOwner != null && flags.profileName != null) {
|
||||
SecurityProfile securityProfile =
|
||||
dspWrapper.getDeviceSecurityProfile(flags.contentOwner, flags.profileName);
|
||||
if (securityProfile == null) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
flags.contentOwner
|
||||
+ " (content owner) and"
|
||||
+ flags.profileName
|
||||
+ " (profile name) "
|
||||
+ "were not found in DeviceSecurityProfiles from "
|
||||
+ flags.query);
|
||||
} else {
|
||||
System.out.println(securityProfile);
|
||||
}
|
||||
} else if (flags.contentOwner != null) {
|
||||
List<SecurityProfile> securityProfiles =
|
||||
dspWrapper.getDeviceSecurityProfiles(flags.contentOwner);
|
||||
if (securityProfiles == null || securityProfiles.isEmpty()) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
flags.contentOwner
|
||||
+ " (content owner) was not found in DeviceSecurityProfiles from "
|
||||
+ flags.query);
|
||||
} else {
|
||||
System.out.println(Arrays.toString(securityProfiles.toArray()));
|
||||
}
|
||||
}
|
||||
if (flags.getOwners) {
|
||||
List<String> ownerList = dspWrapper.getOwners();
|
||||
if (ownerList == null || ownerList.isEmpty()) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
" owner list was not found in DeviceSecurityProfiles from " + flags.query);
|
||||
}
|
||||
System.out.println(Arrays.toString(ownerList.toArray()));
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"InvalidProtocolBufferException encountered while parsing device security profile list"
|
||||
+ " or device security profiles proto:"
|
||||
+ e);
|
||||
} catch (IOException e) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"IOException encountered trying to open device security profiles file: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkLoadFileResult(String filePath, byte[] result) {
|
||||
if (result == null) {
|
||||
logger.log(Level.SEVERE, "Fail to load the file:" + filePath);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load published devices or device security profiles file into string. For published devices v1,
|
||||
* it would be a json file.
|
||||
*
|
||||
* @param filePath file path in String.
|
||||
* @return byte array file content in String.
|
||||
* @throws IOException if failed to read the file.
|
||||
*/
|
||||
public static byte[] getPublishedDevicesOrDspFileAsBytes(String filePath, String dataType)
|
||||
throws IOException {
|
||||
String result = loadFile(filePath);
|
||||
if (!DATA_TYPE_LIST.contains(dataType) || result == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] serializedList;
|
||||
if (dataType.equals(PUBLISHED_DEVICES)) {
|
||||
String requestBody = "";
|
||||
try {
|
||||
// Parse both PublishedDevices v1 output.
|
||||
JSONObject obj = new JSONObject(result);
|
||||
requestBody = obj.getString(JSON_NAME);
|
||||
} catch (JSONException e) {
|
||||
// Parse both PublishedDevices v2 output.
|
||||
requestBody = result;
|
||||
}
|
||||
serializedList = base64Decode(requestBody);
|
||||
} else {
|
||||
serializedList = base64Decode(result);
|
||||
}
|
||||
return serializedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load file into string.
|
||||
*
|
||||
* @param filePath file path in String.
|
||||
* @return String file content in String.
|
||||
* @throws IOException if failed to read the file.
|
||||
*/
|
||||
public static String loadFile(String filePath) throws IOException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
List<String> input = Files.readAllLines(Path.of(filePath));
|
||||
for (String element : input) {
|
||||
result.append(element);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base64-encoded std::string or web-safe base64-encoded string.
|
||||
*
|
||||
* @param base64EncodedData base64 encode data in String.
|
||||
* @return byte[] decoded std::string in byte array.
|
||||
*/
|
||||
public static byte[] base64Decode(String base64EncodedData) {
|
||||
try {
|
||||
return base64().decode(base64EncodedData);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Do nothing. Try the url safe base64 decode next.
|
||||
}
|
||||
return base64Url().decode(base64EncodedData);
|
||||
}
|
||||
|
||||
private PublishedDevicesMain() {}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2020 Google LLC
|
||||
////
|
||||
//// This software is licensed under the terms defined in the Widevine Master
|
||||
//// License Agreement. For a copy of this agreement, please contact
|
||||
//// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
package com.google.video.widevine.jts.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices;
|
||||
import com.google.protobuf.ExtensionRegistry;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatus;
|
||||
import com.google.video.widevine.protos.DeviceCertificateStatusProtos.PublishedDevicesList;
|
||||
import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Wrap the PublishedDevices proto in PublishedDevicesWrapper. */
|
||||
final class PublishedDevicesWrapper {
|
||||
private PublishedDevices publishedDevices = null;
|
||||
private PublishedDevicesList publishedDevicesList = null;
|
||||
private final Map<Integer, DeviceCertificateStatus> dcslMap = new LinkedHashMap<>();
|
||||
|
||||
/** Constructor to create PublishedDevicesWrapper object with {@link PublishedDevices} */
|
||||
public PublishedDevicesWrapper(PublishedDevices publishedDevices)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(publishedDevices, "'published devices' must not be null");
|
||||
this.publishedDevices = publishedDevices;
|
||||
parsePublishedDevicesList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to create PublishedDevicesWrapper object with byte array from {@link
|
||||
* PublishedDevices} serialized proto.
|
||||
*/
|
||||
public PublishedDevicesWrapper(byte[] publishedDevicesInfo)
|
||||
throws InvalidProtocolBufferException {
|
||||
checkNotNull(publishedDevicesInfo, "'published devices' must not be null");
|
||||
publishedDevices =
|
||||
PublishedDevices.parseFrom(publishedDevicesInfo, ExtensionRegistry.getEmptyRegistry());
|
||||
parsePublishedDevicesList();
|
||||
}
|
||||
|
||||
private void parsePublishedDevicesList() throws InvalidProtocolBufferException {
|
||||
publishedDevicesList =
|
||||
PublishedDevicesList.parseFrom(
|
||||
publishedDevices.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry());
|
||||
|
||||
// Add all the original DCSLs into the map.
|
||||
for (DeviceCertificateStatus dcsl : publishedDevicesList.getDeviceCertificateStatusList()) {
|
||||
dcslMap.put(dcsl.getDeviceInfo().getSystemId(), dcsl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PublishedDevicesList .
|
||||
*
|
||||
* @return {@link PublishedDevicesList} field in {@link PublishedDevices}.
|
||||
*/
|
||||
public PublishedDevicesList getPublishedDevicesList() {
|
||||
|
||||
return publishedDevicesList;
|
||||
}
|
||||
/**
|
||||
* Get DeviceCertificateStatus for specific systemId.
|
||||
*
|
||||
* @param systemId systemId in Integer.
|
||||
* @return {@link DeviceCertificateStatus} for specific systemId.
|
||||
*/
|
||||
public DeviceCertificateStatus getDeviceCertificateStatus(int systemId) {
|
||||
return dcslMap.get(systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of PublishedDevicesList.
|
||||
*
|
||||
* @return int Size of PublishedDevicesList.
|
||||
*/
|
||||
public int getSize() {
|
||||
return publishedDevicesList.getDeviceCertificateStatusCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return PublishedDevicesList as a String.
|
||||
*
|
||||
* @return {@link PublishedDevicesList} in String.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return publishedDevicesList.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link PublishedDevicesDelta} by getting delta of new PublishedDevices with current
|
||||
* PublishedDevices.
|
||||
*
|
||||
* @param newPublishedDevices PublishedDevices proto.
|
||||
* @return {@link PublishedDevicesDelta}.
|
||||
* @throws InvalidProtocolBufferException if failed to parse published devices.
|
||||
*/
|
||||
public PublishedDevicesDelta getPublishedDevicesDelta(PublishedDevices newPublishedDevices)
|
||||
throws InvalidProtocolBufferException {
|
||||
PublishedDevicesDeltaWrapper delta =
|
||||
new PublishedDevicesDeltaWrapper(this.publishedDevices, newPublishedDevices);
|
||||
return delta.getDelta();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user