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)
|
([#6876](https://github.com/mitmproxy/mitmproxy/pull/6876), @errorxyz)
|
||||||
* Add an API to parse HTTPS records from DNS RDATA.
|
* Add an API to parse HTTPS records from DNS RDATA.
|
||||||
([#6884](https://github.com/mitmproxy/mitmproxy/pull/6884), @errorxyz)
|
([#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.
|
* Releases now come with a Sigstore attestations file to demonstrate build provenance.
|
||||||
([f05c050](https://github.com/mitmproxy/mitmproxy/commit/f05c050f615b9ab9963707944c893bc94e738525), @mhils)
|
([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 ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.9.3",
|
"@popperjs/core": "^2.11.8",
|
||||||
"bootstrap": "^3.4.1",
|
"bootstrap": "^3.4.1",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"codemirror": "^5.62.3",
|
"codemirror": "^5.62.3",
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^12.0.0",
|
"@testing-library/react": "^12.0.0",
|
||||||
"@testing-library/user-event": "^13.2.1",
|
"@testing-library/user-event": "^13.2.1",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/redux-mock-store": "^1.0.3",
|
"@types/redux-mock-store": "^1.0.3",
|
||||||
"esbuild": "^0.12.21",
|
"esbuild": "^0.12.21",
|
||||||
"esbuild-jest": "^0.5.0",
|
"esbuild-jest": "^0.5.0",
|
||||||
|
@ -43,7 +43,8 @@
|
||||||
"gulp-plumber": "^1.2.1",
|
"gulp-plumber": "^1.2.1",
|
||||||
"gulp-replace": "^1.1.3",
|
"gulp-replace": "^1.1.3",
|
||||||
"gulp-sourcemaps": "^3.0.0",
|
"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",
|
"jest-fetch-mock": "^3.0.3",
|
||||||
"prettier": "2.8.4",
|
"prettier": "2.8.4",
|
||||||
"react-test-renderer": "^17.0.2",
|
"react-test-renderer": "^17.0.2",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`EventList Component should render correctly 1`] = `
|
exports[`EventList Component should render correctly 1`] = `
|
||||||
Object {
|
{
|
||||||
"vScroll": Object {
|
"vScroll": {
|
||||||
"end": 1,
|
"end": 1,
|
||||||
"paddingBottom": 18,
|
"paddingBottom": 18,
|
||||||
"paddingTop": 0,
|
"paddingTop": 0,
|
||||||
|
@ -12,14 +12,14 @@ Object {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`EventList Component should render correctly 2`] = `
|
exports[`EventList Component should render correctly 2`] = `
|
||||||
Object {
|
{
|
||||||
"events": Array [
|
"events": [
|
||||||
Object {
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"level": "info",
|
"level": "info",
|
||||||
"message": "foo",
|
"message": "foo",
|
||||||
},
|
},
|
||||||
Object {
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"level": "error",
|
"level": "error",
|
||||||
"message": "bar",
|
"message": "bar",
|
||||||
|
|
|
@ -10,7 +10,7 @@ exports[`FilterInput Component should render correctly 1`] = `
|
||||||
<i
|
<i
|
||||||
className="fa fa-fw fa-foo"
|
className="fa fa-fw fa-foo"
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"color": "red",
|
"color": "red",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ exports[`EventLog Component should connect to state and render correctly 1`] = `
|
||||||
<div
|
<div
|
||||||
className="eventlog"
|
className="eventlog"
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"height": 200,
|
"height": 200,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
||||||
<table>
|
<table>
|
||||||
<thead
|
<thead
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"transform": "translateY(0px)",
|
"transform": "translateY(0px)",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"height": 0,
|
"height": 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
||||||
<td
|
<td
|
||||||
className="col-status"
|
className="col-status"
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"color": "darkgreen",
|
"color": "darkgreen",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ exports[`FlowTable Component should render correctly 1`] = `
|
||||||
</tr>
|
</tr>
|
||||||
<tr
|
<tr
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"height": 0,
|
"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 { Flow } from "../flow";
|
||||||
import { copyToClipboard } from "../contrib/clipboard";
|
|
||||||
|
|
||||||
export const copy = async (flow: Flow, format: string): Promise<void> => {
|
export const copy = async (flow: Flow, format: string): Promise<void> => {
|
||||||
let ret = await runCommand("export", format, `@${flow.id}`);
|
// Safari: We need to call copyToClipboard _right away_ with a promise,
|
||||||
if (ret.value) {
|
// otherwise we're loosing user intent and can't copy anymore.
|
||||||
await copyToClipboard(ret.value);
|
let formatted = (async () => {
|
||||||
} else if (ret.error) {
|
let ret = await runCommand("export", format, `@${flow.id}`);
|
||||||
alert(ret.error);
|
if (ret.value) {
|
||||||
} else {
|
return ret.value;
|
||||||
console.error(ret);
|
} 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;
|
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