summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
blob: 442a3c5fb9f8045abe8a63d24e6d4fd740d039b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_WRITER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_WRITER_H_

#include "base/sequence_checker.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
#include "third_party/skia/include/core/SkImage.h"

namespace blink {

class FileReaderLoader;
class SystemClipboard;
class RawSystemClipboard;

// Interface for writing an individual Clipboard API format as a Blob to the
// System Clipboard, safely and asynchronously.
//
// ClipboardWriter takes as input a ClipboardPromise, which manages writing
// multiple formats and passes in unsanitized clipboard payloads.
// ClipboardWriter then sanitizes a Blob payload and writes it onto the
// underlying system clipboard. All System Clipboard operations should be
// called from the main thread.
//
// Writing a Blob's data to the system clipboard is accomplished by:
// (1) Reading - the Blob's contents using a FileReaderLoader.
// (2) Decoding - or sanitizing the Blob's contents to avoid RCE in native
//     applications that may take advantage of vulnerabilities in their
//     decoders, whenever possible. Decoding may be time-consuming, so it
//     is done on a background thread whenever possible. An example where
//     decoding is done on the main thread is HTML, where Blink's HTML decoder
//     can only be used on the main thread.
// (3) Writing - the Blob's decoded contents to the system clipboard.
//
// Subclasses of ClipboardWriter should be implemented for each supported
// format. Subclasses should:
// (1) Begin execution by implementing ClipboardWriter::StartWrite().
// (2) Decode the payload on a background thread (if possible) by implementing
//     a static DecodeOnBackgroundThread() function. This function is called by
//     StartWrite() via worker_pool::PostTask().
// (3) Write the decoded content to the system clipboard by implementing
//     ClipboardWriter::Write();
//
// ClipboardWriter is owned only by itself and ClipboardPromise. It keeps
// itself alive for the duration of FileReaderLoader's async operations using
// SelfKeepAlive, and keeps itself alive afterwards during cross-thread
// operations by using WrapCrossThreadPersistent.
class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
                        public FileReaderLoaderClient {
 public:
  // For writing sanitized MIME types.
  // IsValidType() must return true on types passed into `mime_type`.
  static ClipboardWriter* Create(SystemClipboard* system_clipboard,
                                 const String& mime_type,
                                 ClipboardPromise* promise);
  // For writing unsanitized types.
  // IsValidType() must return true on types passed into `mime_type`.
  static ClipboardWriter* Create(RawSystemClipboard* raw_system_clipboard,
                                 const String& mime_type,
                                 ClipboardPromise* promise);
  ~ClipboardWriter() override;

  // Returns whether ClipboardWriter has implemented support for this type.
  //
  // IsValidType() is expected to be called before Create(). If it returns false
  // for a `mime_type`, Create() must not be called with that `mime_type`.
  //
  // IsValidType() is used for both ClipboardWriter and ClipboardReader, as read
  // and write currently support the same types. If this changes in the future,
  // please create separate IsValidType functions.
  static bool IsValidType(const String& mime_type, bool is_raw);
  // Begins the sequence of writing the Blob to the system clipbaord.
  void WriteToSystem(Blob* blob);

  // FileReaderLoaderClient.
  void DidStartLoading() override;
  void DidReceiveData() override;
  void DidFinishLoading() override;
  void DidFail(FileErrorCode) override;

  void Trace(Visitor*) const;

 protected:
  ClipboardWriter(SystemClipboard* system_clipboard, ClipboardPromise* promise);
  ClipboardWriter(RawSystemClipboard* raw_system_clipboard,
                  ClipboardPromise* promise);

  // Decodes and writes `raw_data`. Decoding is done off the main thread
  // whenever possible, by calling DecodeOnBackgroundThread.
  virtual void StartWrite(
      DOMArrayBuffer* raw_data,
      scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;

  // SystemClipboard and RawSystemClipboard are bound to LocalFrame, so the
  // bound LocalFrame must still be valid by the time they're used.
  SystemClipboard* system_clipboard() {
    DCHECK(promise_->GetLocalFrame());
    return system_clipboard_;
  }

  RawSystemClipboard* raw_system_clipboard() {
    DCHECK(promise_->GetLocalFrame());
    return raw_system_clipboard_;
  }

  // This ClipboardPromise owns this ClipboardWriter. Subclasses use `promise_`
  // to report success or failure, or to obtain the execution context.
  Member<ClipboardPromise> promise_;

  // Every subclass method that runs on the main thread should
  // DCHECK_CALLED_ON_VALID_SEQUENCE with this checker.
  SEQUENCE_CHECKER(sequence_checker_);

 private:
  ClipboardWriter(SystemClipboard* system_clipboard,
                  RawSystemClipboard* raw_system_clipboard,
                  ClipboardPromise* promise);
  // TaskRunner for interacting with the system clipboard.
  const scoped_refptr<base::SingleThreadTaskRunner> clipboard_task_runner_;
  // TaskRunner for reading files.
  const scoped_refptr<base::SingleThreadTaskRunner> file_reading_task_runner_;
  // This FileReaderLoader will load the Blob.
  std::unique_ptr<FileReaderLoader> file_reader_;
  // Access to the global sanitized system clipboard.
  Member<SystemClipboard> system_clipboard_;
  // Access to the global unsanitized system clipboard.
  Member<RawSystemClipboard> raw_system_clipboard_;

  // Oilpan: ClipboardWriter must remain alive until Member<T>::Clear() is
  // called, to keep the FileReaderLoader alive and avoid unexpected UaPs.
  SelfKeepAlive<ClipboardWriter> self_keep_alive_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_CLIPBOARD_CLIPBOARD_WRITER_H_