Fix clipboard handling in safari (#6917)
* fix clipboard handling in safari closes #6911, #6909 Co-authored-by: Can Yesilyurt <36952967+canyesilyurt@users.noreply.github.com> * [autofix.ci] apply automated fixes * update dependencies --------- Co-authored-by: Can Yesilyurt <36952967+canyesilyurt@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
40ae9ff05b
commit
832e735b0a
|
@ -21,6 +21,8 @@
|
|||
([#6876](https://github.com/mitmproxy/mitmproxy/pull/6876), @errorxyz)
|
||||
* Add an API to parse HTTPS records from DNS RDATA.
|
||||
([#6884](https://github.com/mitmproxy/mitmproxy/pull/6884), @errorxyz)
|
||||
* Fix flow export in mitmweb for Safari
|
||||
([#6917](https://github.com/mitmproxy/mitmproxy/pull/6917), @mhils, @canyesilyurt)
|
||||
* Releases now come with a Sigstore attestations file to demonstrate build provenance.
|
||||
([f05c050](https://github.com/mitmproxy/mitmproxy/commit/f05c050f615b9ab9963707944c893bc94e738525), @mhils)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@
|
|||
"prettier": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.3",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"bootstrap": "^3.4.1",
|
||||
"classnames": "^2.3.1",
|
||||
"codemirror": "^5.62.3",
|
||||
|
@ -29,7 +29,7 @@
|
|||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/redux-mock-store": "^1.0.3",
|
||||
"esbuild": "^0.12.21",
|
||||
"esbuild-jest": "^0.5.0",
|
||||
|
@ -43,7 +43,8 @@
|
|||
"gulp-plumber": "^1.2.1",
|
||||
"gulp-replace": "^1.1.3",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"jest": "^27.0.6",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"prettier": "2.8.4",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`EventList Component should render correctly 1`] = `
|
||||
Object {
|
||||
"vScroll": Object {
|
||||
{
|
||||
"vScroll": {
|
||||
"end": 1,
|
||||
"paddingBottom": 18,
|
||||
"paddingTop": 0,
|
||||
|
@ -12,14 +12,14 @@ Object {
|
|||
`;
|
||||
|
||||
exports[`EventList Component should render correctly 2`] = `
|
||||
Object {
|
||||
"events": Array [
|
||||
Object {
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"id": 1,
|
||||
"level": "info",
|
||||
"message": "foo",
|
||||
},
|
||||
Object {
|
||||
{
|
||||
"id": 2,
|
||||
"level": "error",
|
||||
"message": "bar",
|
||||
|
|
|
@ -10,7 +10,7 @@ exports[`FilterInput Component should render correctly 1`] = `
|
|||
<i
|
||||
className="fa fa-fw fa-foo"
|
||||
style={
|
||||
Object {
|
||||
{
|
||||
"color": "red",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ exports[`EventLog Component should connect to state and render correctly 1`] = `
|
|||
<div
|
||||
className="eventlog"
|
||||
style={
|
||||
Object {
|
||||
{
|
||||
"height": 200,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
|||
<table>
|
||||
<thead
|
||||
style={
|
||||
Object {
|
||||
{
|
||||
"transform": "translateY(0px)",
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
|||
<tbody>
|
||||
<tr
|
||||
style={
|
||||
Object {
|
||||
{
|
||||
"height": 0,
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
|||
<td
|
||||
className="col-status"
|
||||
style={
|
||||
Object {
|
||||
{
|
||||
"color": "darkgreen",
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
|||
</tr>
|
||||
<tr
|
||||
style={
|
||||
Object {
|
||||
{
|
||||
"height": 0,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
// Adapted from https://stackoverflow.com/a/65996386/934719
|
||||
/**
|
||||
* `navigator.clipboard.writeText()`, but with an additional fallback for non-secure contexts.
|
||||
*/
|
||||
export function copyToClipboard(text: string): Promise<void> {
|
||||
// navigator clipboard requires a security context such as https
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
return navigator.clipboard.writeText(text);
|
||||
} else {
|
||||
let t = document.createElement("textarea");
|
||||
t.value = text;
|
||||
t.style.position = "absolute";
|
||||
t.style.opacity = "0";
|
||||
document.body.appendChild(t);
|
||||
try {
|
||||
t.focus();
|
||||
t.select();
|
||||
document.execCommand("copy");
|
||||
return Promise.resolve();
|
||||
} catch (err) {
|
||||
alert(text);
|
||||
return Promise.reject(err);
|
||||
} finally {
|
||||
t.remove();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,22 @@
|
|||
import { runCommand } from "../utils";
|
||||
import { copyToClipboard, runCommand } from "../utils";
|
||||
import { Flow } from "../flow";
|
||||
import { copyToClipboard } from "../contrib/clipboard";
|
||||
|
||||
export const copy = async (flow: Flow, format: string): Promise<void> => {
|
||||
let ret = await runCommand("export", format, `@${flow.id}`);
|
||||
if (ret.value) {
|
||||
await copyToClipboard(ret.value);
|
||||
} else if (ret.error) {
|
||||
alert(ret.error);
|
||||
} else {
|
||||
console.error(ret);
|
||||
// Safari: We need to call copyToClipboard _right away_ with a promise,
|
||||
// otherwise we're loosing user intent and can't copy anymore.
|
||||
let formatted = (async () => {
|
||||
let ret = await runCommand("export", format, `@${flow.id}`);
|
||||
if (ret.value) {
|
||||
return ret.value;
|
||||
} else if (ret.error) {
|
||||
throw ret.error;
|
||||
} else {
|
||||
throw ret;
|
||||
}
|
||||
})();
|
||||
try {
|
||||
await copyToClipboard(formatted);
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -135,3 +135,50 @@ export function getDiff(obj1, obj2) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* `navigator.clipboard.writeText()`, but with an additional fallback for non-secure contexts.
|
||||
*
|
||||
* Never throws unless textPromise is rejected.
|
||||
*/
|
||||
export async function copyToClipboard(
|
||||
textPromise: Promise<string>
|
||||
): Promise<void> {
|
||||
// Try the new clipboard APIs first. If that fails, use textarea fallback.
|
||||
try {
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
"text/plain": textPromise,
|
||||
}),
|
||||
]);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
|
||||
let text = await textPromise;
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
|
||||
let t = document.createElement("textarea");
|
||||
t.value = text;
|
||||
t.style.position = "absolute";
|
||||
t.style.opacity = "0";
|
||||
document.body.appendChild(t);
|
||||
try {
|
||||
t.focus();
|
||||
t.select();
|
||||
if (!document.execCommand("copy")) {
|
||||
throw "failed to copy";
|
||||
}
|
||||
} catch {
|
||||
alert(text);
|
||||
} finally {
|
||||
t.remove();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue