// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_page_selector/cr_page_selector.js';
import 'chrome://resources/cr_elements/cr_tabs/cr_tabs.js';
import '//resources/cr_elements/cr_collapse/cr_collapse.js';
import '//resources/cr_elements/cr_expand_button/cr_expand_button.js';
import './strings.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {ContentRestriction, DataTransferEndpoint, DlpEvent, DlpEvent_Mode, DlpEvent_Restriction, DlpEvent_UserType, EndpointType, EventDestination, FileDatabaseEntry, Level, PageHandlerInterface, WebContentsInfo} from './dlp_internals.mojom-webui.js';
import {PageHandler, ReportingObserverReceiver} from './dlp_internals.mojom-webui.js';
import {getTemplate} from './dlp_internals_ui.html.js';
import {ContentRestrictionMap, DestinationComponentMap, EndpointTypeMap, EventModeMap, EventRestrictionMap, EventUserTypeMap, LevelMap, WebContentsElement} from './dlp_utils.js';
// Polymer element DLP Internals UI.
class DlpInternalsUi extends PolymerElement {
static get is() {
return 'dlp-internals-ui';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
isOtr_: Boolean,
doRulesManagerExist_: Boolean,
showTabs_: Boolean,
selectedTabIdx_: Number,
tabNames_: Array,
clipboardSourceType_: String,
clipboardSourceUrl_: String,
reportingEvents_: Array,
webContentsElements_: Array,
};
}
override connectedCallback() {
super.connectedCallback();
this.fetchClipboardSourceInfo();
this.fetchContentRestrictionsInfo();
this.fetchFilesDatabaseEntries();
}
// Names of the top level page tabs.
private tabNames_: string[] = [
'Clipboard',
'OnScreen',
'Files',
'Reporting',
];
// Whether the profle is off the record.
private isOtr_: boolean = false;
// Whether DLP rules manager exists.
private doRulesManagerExist_: boolean = false;
// Whether the page tabs show be added.
private showTabs_: boolean = false;
// Index of the selected top level page tab.
private selectedTabIdx_: number = 0;
// Clipboard source type string.
private clipboardSourceType_: string;
// Clipboard source url.
private clipboardSourceUrl_: string;
// Reporting events array.
private reportingEvents_: DlpEvent[] = [];
// Web Contents Info.
private webContentsElements_: WebContentsElement[] = [];
// Files Database Entries.
private filesEntries_: FileDatabaseEntry[] = [];
// Selected file inode number.
private selectedFileInode_: bigint;
private readonly pageHandler_: PageHandlerInterface;
private readonly reportingObserver_: ReportingObserverReceiver;
constructor() {
super();
if (loadTimeData.valueExists('isOtr')) {
this.isOtr_ = loadTimeData.getBoolean('isOtr');
}
if (loadTimeData.valueExists('doRulesManagerExist')) {
this.doRulesManagerExist_ =
loadTimeData.getBoolean('doRulesManagerExist');
}
this.showTabs_ = !this.isOtr_ && this.doRulesManagerExist_;
this.pageHandler_ = PageHandler.getRemote();
this.reportingObserver_ = new ReportingObserverReceiver(this);
this.pageHandler_.observeReporting(
this.reportingObserver_.$.bindNewPipeAndPassRemote());
}
private async fetchClipboardSourceInfo(): Promise<void> {
this.pageHandler_.getClipboardDataSource()
.then((value: {source: DataTransferEndpoint|null}) => {
this.setClipboardInfo(value.source);
})
.catch((e: object) => {
console.warn(`getClipboardDataSource failed: ${JSON.stringify(e)}`);
});
}
private setClipboardInfo(source: DataTransferEndpoint|null|undefined) {
if (!source) {
this.clipboardSourceType_ = 'undefined';
this.clipboardSourceUrl_ = 'undefined';
return;
}
this.clipboardSourceType_ = `${this.endpointTypeToString(source.type)}`;
if (source.url === null) {
this.clipboardSourceUrl_ = 'undefined';
} else {
this.clipboardSourceUrl_ = source.url.url;
}
}
private endpointTypeToString(type: EndpointType): string {
return EndpointTypeMap[type] || 'invalid';
}
private async fetchContentRestrictionsInfo(): Promise<void> {
this.pageHandler_.getContentRestrictionsInfo()
.then((value: {webContentsInfo: WebContentsInfo[]}) => {
this.setWebContentsInfo(value.webContentsInfo);
})
.catch((e: object) => {
console.warn(
`getContentRestrictionsInfo failed: ${JSON.stringify(e)}`);
});
}
private setWebContentsInfo(webContentsInfo: WebContentsInfo[]) {
this.webContentsElements_ = [];
for (const info of webContentsInfo) {
this.webContentsElements_.push(new WebContentsElement(info));
}
if (webContentsInfo.length) {
this.notifySplices('webContentsElements_', [{
index: 0,
addedCount: this.webContentsElements_.length,
object: this.webContentsElements_,
type: 'splice',
removed: [],
}]);
}
}
private async fetchFilesDatabaseEntries(): Promise<void> {
this.pageHandler_.getFilesDatabaseEntries()
.then((value: {dbEntries: FileDatabaseEntry[]}) => {
this.setFilesDatabaseEntries(value.dbEntries);
})
.catch((e: object) => {
console.warn(`getFilesDatabaseEntries failed: ${JSON.stringify(e)}`);
});
}
private setFilesDatabaseEntries(entries: FileDatabaseEntry[]) {
this.filesEntries_ = entries;
if (entries.length) {
this.notifySplices('filesEntries_', [{
index: 0,
addedCount: this.filesEntries_.length,
object: this.filesEntries_,
type: 'splice',
removed: [],
}]);
}
}
/** Implements ReportingObserverInterface */
onReportEvent(event: DlpEvent): void {
this.reportingEvents_.push(event);
this.notifySplices('reportingEvents_', [{
index: this.reportingEvents_.length - 1,
addedCount: 1,
object: this.reportingEvents_,
type: 'splice',
removed: [],
}]);
}
destinationToString(destination: EventDestination|null|undefined): string {
if (destination) {
if (destination.urlPattern) {
return destination.urlPattern;
}
if (destination.component) {
return DestinationComponentMap[destination.component];
}
}
return 'undefined';
}
restrictionToString(restriction: DlpEvent_Restriction|null|
undefined): string {
if (restriction) {
return EventRestrictionMap[restriction];
}
return 'undefined';
}
modeToString(mode: DlpEvent_Mode|null|undefined): string {
if (mode) {
return EventModeMap[mode];
}
return 'undefined';
}
userTypeToString(userType: DlpEvent_UserType|null|undefined): string {
if (userType) {
return EventUserTypeMap[userType];
}
return 'undefined';
}
timestampToString(timestampMicro: bigint): string {
if (timestampMicro) {
const timestampMilli: number = Number(timestampMicro) / 1000;
const timestamp: Date = new Date(timestampMilli);
return timestamp.toLocaleString();
}
return 'undefined';
}
contentRestrictionToString(restriction: ContentRestriction): string {
return ContentRestrictionMap[restriction];
}
levelToString(level: Level): string {
return LevelMap[level];
}
creationTimeToString(timestampSeconds: bigint): string {
if (timestampSeconds) {
const timestampMilli: number = Number(timestampSeconds) * 1000;
const timestamp: Date = new Date(timestampMilli);
return timestamp.toLocaleString();
}
return 'undefined';
}
private onFileSelected(e: Event) {
const selectedFile = (e.target as HTMLInputElement).value;
this.pageHandler_.getFileInode(selectedFile.replace('C:\\fakepath\\', ''))
.then((value: {inode: bigint|null}) => {
if (value.inode) {
this.selectedFileInode_ = value.inode;
} else {
this.selectedFileInode_ = BigInt(0);
}
})
.catch((e: object) => {
console.warn(`getFileInode failed: ${JSON.stringify(e)}`);
});
}
}
customElements.define(DlpInternalsUi.is, DlpInternalsUi);