mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 16:51:55 +00:00
upgrade browser extension to manifest v3
Chrome's and the Chrome Web Store's push for [Manifest V3](https://developer.chrome.com/docs/extensions/develop/migrate) means that our browser extension will start to be unusable in a few months unless we upgrade to Manifest V3. - Removes "Enable Sourcegraph on this domain" context menu item that didn't seem to work. We were adding this ourselves (using `webext-domain-permission-toggle`), and it didn't seem to work. Our options popup shows a permission request, which is sufficient. - Otherwise preserves all existing functionality as best I could tell. Test plan: 1. Confirm that the browser extension continues to inject the Sourcegraph icon on https://github.com/hashicorp/errwrap. 1. Load up https://gitlab.com/sqs/web in my local dev Sourcegraph instance and confirm that the browser extension injects the Sourcegraph icon on https://gitlab.com/sqs/web code files.
This commit is contained in:
parent
341bfe749f
commit
8fb7f19310
@ -262,7 +262,6 @@ ts_project(
|
||||
"//:node_modules/utility-types",
|
||||
"//:node_modules/uuid",
|
||||
"//:node_modules/vitest",
|
||||
"//:node_modules/webext-domain-permission-toggle",
|
||||
"//:node_modules/webextension-polyfill", #keep
|
||||
],
|
||||
)
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/webextension",
|
||||
"$schema": "https://json.schemastore.org/chrome-manifest",
|
||||
"version": "0.0.0",
|
||||
"name": "Sourcegraph",
|
||||
"manifest_version": 2,
|
||||
"manifest_version": 3,
|
||||
"description": "Adds code intelligence to GitHub, GitLab, and other hosts: hovers, definitions, references. For 20+ languages.",
|
||||
"browser_action": {
|
||||
"action": {
|
||||
"default_title": "Sourcegraph",
|
||||
"default_icon": {
|
||||
"32": "img/icon-32.png",
|
||||
"48": "img/icon-48.png",
|
||||
"128": "img/icon-128.png"
|
||||
}
|
||||
},
|
||||
"default_popup": "options.html"
|
||||
},
|
||||
"icons": {
|
||||
"32": "img/icon-32.png",
|
||||
@ -18,8 +19,18 @@
|
||||
"128": "img/icon-128.png"
|
||||
},
|
||||
"background": {
|
||||
"scripts": ["js/backgroundPage.main.bundle.js"]
|
||||
"service_worker": "js/backgroundPage.main.bundle.js"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["https://github.com/*"],
|
||||
"js": ["js/contentPage.main.bundle.js"],
|
||||
"run_at": "document_idle"
|
||||
}
|
||||
],
|
||||
"permissions": ["activeTab", "storage"],
|
||||
"host_permissions": ["https://github.com/*", "https://sourcegraph.com/*"],
|
||||
"optional_host_permissions": ["https://*/*", "http://*/*"],
|
||||
"options_ui": {
|
||||
"page": "options.html",
|
||||
"open_in_tab": true
|
||||
@ -27,31 +38,21 @@
|
||||
"storage": {
|
||||
"managed_schema": "schema.json"
|
||||
},
|
||||
"optional_permissions": ["tabs", "http://*/*", "https://*/*"],
|
||||
"content_security_policy": "script-src 'self' blob:; object-src 'self'",
|
||||
"web_accessible_resources": ["img/*", "css/*"],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": ["img/*", "css/*"],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
],
|
||||
"omnibox": {
|
||||
"keyword": "src"
|
||||
},
|
||||
"applications": {
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "sourcegraph-for-firefox@sourcegraph.com"
|
||||
}
|
||||
},
|
||||
"dev": {
|
||||
"permissions": [
|
||||
"storage",
|
||||
"activeTab",
|
||||
"contextMenus",
|
||||
"https://github.com/*",
|
||||
"https://gitlab.com/*",
|
||||
"https://localhost:3443/*",
|
||||
"https://sourcegraph.com/*",
|
||||
"http://localhost:32773/*"
|
||||
],
|
||||
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl2X/axNHMbP0K/NCpMzGo/pgBSsHB2xKx6tfohORKtEv2wUMBPmkK3++kirrwYO2f8Ficyq6pjlXV8LjwPSjSw9KZj6bkDn8QNoSdCp6x9i8ZOWPw6UTQ6s54b3rGQNyvrvfD7S6LphxGEx8rNlkjpWKcrvY3+DyoFKHP/hax7wIDAQAB"
|
||||
},
|
||||
"prod": {
|
||||
"permissions": ["activeTab", "storage", "contextMenus", "https://github.com/*", "https://sourcegraph.com/*"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,6 @@ import {
|
||||
catchError,
|
||||
distinctUntilChanged,
|
||||
} from 'rxjs/operators'
|
||||
import addDomainPermissionToggle from 'webext-domain-permission-toggle'
|
||||
|
||||
import { isDefined, fetchCache } from '@sourcegraph/common'
|
||||
import { type GraphQLResult, requestGraphQLCommon } from '@sourcegraph/http-client'
|
||||
@ -293,9 +292,6 @@ async function main(): Promise<void> {
|
||||
// loaded in the popup or in th standalone options page.
|
||||
browser.browserAction.setPopup({ popup: 'options.html?popup=true' })
|
||||
|
||||
// Add "Enable Sourcegraph on this domain" context menu item
|
||||
addDomainPermissionToggle()
|
||||
|
||||
const ENDPOINT_KIND_REGEX = /^(proxy|expose)-/
|
||||
|
||||
const portKind = (port: browser.runtime.Port): string | undefined => {
|
||||
|
||||
@ -162,7 +162,10 @@ declare namespace browser.browserAction {
|
||||
function openPopup(): Promise<void>
|
||||
function setBadgeText(details: { text: string | null; tabId?: number }): void
|
||||
function getBadgeText(details: { tabId?: number }): Promise<string>
|
||||
function setBadgeBackgroundColor(details: { color: string | ColorArray | null; tabId?: number }): void
|
||||
function setBadgeBackgroundColor(details: {
|
||||
color: string | ColorArray | null
|
||||
tabId?: number
|
||||
}): void
|
||||
function getBadgeBackgroundColor(details: { tabId?: number }): Promise<ColorArray>
|
||||
|
||||
interface SetBadgeTextColorDetails {
|
||||
@ -176,12 +179,10 @@ declare namespace browser.browserAction {
|
||||
}
|
||||
function setBadgeTextColor(details: SetBadgeTextColorDetails & { tabId?: number }): void
|
||||
// a union type would allow specifying both, which is not allowed.
|
||||
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
||||
function setBadgeTextColor(details: SetBadgeTextColorDetails & { windowId?: number }): void
|
||||
|
||||
function getBadgeTextColor(details: { tabId?: string }): Promise<ColorArray>
|
||||
// a union type would allow specifying both, which is not allowed.
|
||||
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
||||
function getBadgeTextColor(details: { windowId?: string }): Promise<ColorArray>
|
||||
|
||||
function enable(tabId?: number): void
|
||||
@ -342,7 +343,11 @@ declare namespace browser.contextualIdentities {
|
||||
name: string
|
||||
}
|
||||
|
||||
function create(details: { name: string; color: IdentityColor; icon: IdentityIcon }): Promise<ContextualIdentity>
|
||||
function create(details: {
|
||||
name: string
|
||||
color: IdentityColor
|
||||
icon: IdentityIcon
|
||||
}): Promise<ContextualIdentity>
|
||||
function get(cookieStoreId: string): Promise<ContextualIdentity | null>
|
||||
function query(details: { name?: string }): Promise<ContextualIdentity[]>
|
||||
function update(
|
||||
@ -424,13 +429,19 @@ declare namespace browser.contentScripts {
|
||||
unregister: () => void
|
||||
}
|
||||
|
||||
function register(contentScriptOptions: RegisteredContentScriptOptions): Promise<RegisteredContentScript>
|
||||
function register(
|
||||
contentScriptOptions: RegisteredContentScriptOptions
|
||||
): Promise<RegisteredContentScript>
|
||||
}
|
||||
|
||||
declare namespace browser.devtools.inspectedWindow {
|
||||
const tabId: number
|
||||
|
||||
function reload(reloadOptions?: { ignoreCache?: boolean; userAgent?: string; injectedScript?: string }): void
|
||||
function reload(reloadOptions?: {
|
||||
ignoreCache?: boolean
|
||||
userAgent?: string
|
||||
injectedScript?: string
|
||||
}): void
|
||||
}
|
||||
|
||||
declare namespace browser.devtools.network {
|
||||
@ -690,7 +701,10 @@ declare namespace browser.history {
|
||||
|
||||
function deleteUrl(details: { url: string }): Promise<void>
|
||||
|
||||
function deleteRange(range: { startTime: number | string | Date; endTime: number | string | Date }): Promise<void>
|
||||
function deleteRange(range: {
|
||||
startTime: number | string | Date
|
||||
endTime: number | string | Date
|
||||
}): Promise<void>
|
||||
|
||||
function deleteAll(): Promise<void>
|
||||
|
||||
@ -787,8 +801,12 @@ declare namespace browser.omnibox {
|
||||
function setDefaultSuggestion(suggestion: { description: string }): void
|
||||
|
||||
const onInputStarted: EventEmitter<void>
|
||||
const onInputChanged: CallbackEventEmitter<(text: string, suggest: (arg: SuggestResult[]) => void) => void>
|
||||
const onInputEntered: CallbackEventEmitter<(text: string, disposition: OnInputEnteredDisposition) => void>
|
||||
const onInputChanged: CallbackEventEmitter<
|
||||
(text: string, suggest: (arg: SuggestResult[]) => void) => void
|
||||
>
|
||||
const onInputEntered: CallbackEventEmitter<
|
||||
(text: string, disposition: OnInputEnteredDisposition) => void
|
||||
>
|
||||
const onInputCancelled: EventEmitter<void>
|
||||
}
|
||||
|
||||
@ -803,7 +821,11 @@ declare namespace browser.pageAction {
|
||||
|
||||
function getTitle(details: { tabId: number }): Promise<string>
|
||||
|
||||
function setIcon(details: { tabId: number; path?: string | object; imageData?: ImageDataType }): Promise<void>
|
||||
function setIcon(details: {
|
||||
tabId: number
|
||||
path?: string | object
|
||||
imageData?: ImageDataType
|
||||
}): Promise<void>
|
||||
|
||||
function setPopup(details: { tabId: number; popup: string }): void
|
||||
|
||||
@ -1403,7 +1425,10 @@ declare namespace browser.tabs {
|
||||
function captureVisibleTab(windowId?: number, options?: extensionTypes.ImageDetails): Promise<string>
|
||||
function detectLanguage(tabId?: number): Promise<string>
|
||||
function duplicate(tabId: number): Promise<Tab>
|
||||
function executeScript(tabId: number | undefined, details: extensionTypes.InjectDetails): Promise<object[]>
|
||||
function executeScript(
|
||||
tabId: number | undefined,
|
||||
details: extensionTypes.InjectDetails
|
||||
): Promise<object[]>
|
||||
function get(tabId: number): Promise<Tab>
|
||||
// deprecated: function getAllInWindow(): x;
|
||||
function getCurrent(): Promise<Tab>
|
||||
@ -1415,7 +1440,10 @@ declare namespace browser.tabs {
|
||||
// windowId?: number,
|
||||
// tabs: number[]|number,
|
||||
// }): Promise<browser.windows.Window>;
|
||||
function insertCSS(tabId: number | undefined, details: extensionTypes.InjectDetailsCSS): Promise<void>
|
||||
function insertCSS(
|
||||
tabId: number | undefined,
|
||||
details: extensionTypes.InjectDetailsCSS
|
||||
): Promise<void>
|
||||
function removeCSS(tabId: number | undefined, details: extensionTypes.InjectDetails): Promise<void>
|
||||
function move(
|
||||
tabIds: number | number[],
|
||||
@ -1930,7 +1958,10 @@ declare namespace browser.windows {
|
||||
|
||||
function getCurrent(getInfo?: { populate?: boolean; windowTypes?: WindowType[] }): Promise<Window>
|
||||
|
||||
function getLastFocused(getInfo?: { populate?: boolean; windowTypes?: WindowType[] }): Promise<Window>
|
||||
function getLastFocused(getInfo?: {
|
||||
populate?: boolean
|
||||
windowTypes?: WindowType[]
|
||||
}): Promise<Window>
|
||||
|
||||
function getAll(getInfo?: { populate?: boolean; windowTypes?: WindowType[] }): Promise<Window[]>
|
||||
|
||||
|
||||
@ -427,7 +427,6 @@
|
||||
"utility-types": "^3.10.0",
|
||||
"uuid": "^8.3.0",
|
||||
"vscode-uri": "^3.0.7",
|
||||
"webext-domain-permission-toggle": "^1.0.1",
|
||||
"webextension-polyfill": "^0.6.0",
|
||||
"whatwg-url": "^14.0.0",
|
||||
"yaml-ast-parser": "^0.0.43",
|
||||
|
||||
@ -487,9 +487,6 @@ importers:
|
||||
vscode-uri:
|
||||
specifier: ^3.0.7
|
||||
version: 3.0.7
|
||||
webext-domain-permission-toggle:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
webextension-polyfill:
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0
|
||||
@ -6037,7 +6034,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/fake-timers': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
jest-mock: 29.7.0
|
||||
dev: false
|
||||
|
||||
@ -6047,7 +6044,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
'@sinonjs/fake-timers': 10.3.0
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
jest-message-util: 29.7.0
|
||||
jest-mock: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
@ -6086,7 +6083,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/istanbul-lib-coverage': 2.0.6
|
||||
'@types/istanbul-reports': 3.0.4
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
'@types/yargs': 15.0.19
|
||||
chalk: 4.1.2
|
||||
dev: false
|
||||
@ -6109,7 +6106,7 @@ packages:
|
||||
'@jest/schemas': 29.6.3
|
||||
'@types/istanbul-lib-coverage': 2.0.6
|
||||
'@types/istanbul-reports': 3.0.4
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
'@types/yargs': 17.0.23
|
||||
chalk: 4.1.2
|
||||
|
||||
@ -10337,7 +10334,7 @@ packages:
|
||||
'@storybook/preview-api': 7.6.17
|
||||
'@storybook/theming': 7.6.17(react-dom@18.1.0)(react@18.1.0)
|
||||
'@storybook/types': 7.6.17
|
||||
'@types/lodash': 4.17.0
|
||||
'@types/lodash': 4.14.167
|
||||
color-convert: 2.0.1
|
||||
dequal: 2.0.3
|
||||
lodash: 4.17.21
|
||||
@ -11976,13 +11973,6 @@ packages:
|
||||
'@types/responselike': 1.0.0
|
||||
dev: false
|
||||
|
||||
/@types/chrome@0.0.106:
|
||||
resolution: {integrity: sha512-sCQa+QJL/Kl+6ngU4xD1VjTFIkQDizOHN94zbb7byK9D3U79x/KXjqXyS7lHoa2q9xw3bWePb+giLhBKOILRuA==}
|
||||
dependencies:
|
||||
'@types/filesystem': 0.0.29
|
||||
'@types/har-format': 1.2.4
|
||||
dev: false
|
||||
|
||||
/@types/chrome@0.0.127:
|
||||
resolution: {integrity: sha512-hBB9EApLYKKn2GvklVkTxVP6vZvxsH9okyIRUinNtMzZHIgIKWQk/ESbX+O5g4Bihfy38+aFGn7Kl7Cxou5JUg==}
|
||||
dependencies:
|
||||
@ -12184,9 +12174,11 @@ packages:
|
||||
resolution: {integrity: sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==}
|
||||
dependencies:
|
||||
'@types/filewriter': 0.0.28
|
||||
dev: true
|
||||
|
||||
/@types/filewriter@0.0.28:
|
||||
resolution: {integrity: sha512-AR2KUJIMdSfl/SaAHpRotBAlaJpmhgHwehEeSJQOG0hS3IrjDU16xUEEUTdqcvdLa1q16ZK5MMrtOagfLvm0gw==}
|
||||
dev: true
|
||||
|
||||
/@types/find-cache-dir@3.2.1:
|
||||
resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==}
|
||||
@ -12214,11 +12206,12 @@ packages:
|
||||
/@types/graceful-fs@4.1.5:
|
||||
resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==}
|
||||
dependencies:
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
dev: true
|
||||
|
||||
/@types/har-format@1.2.4:
|
||||
resolution: {integrity: sha512-iUxzm1meBm3stxUMzRqgOVHjj4Kgpgu5w9fm4X7kPRfSgVRzythsucEN7/jtOo8SQzm+HfcxWWzJS0mJDH/3DQ==}
|
||||
dev: true
|
||||
|
||||
/@types/hast@2.3.1:
|
||||
resolution: {integrity: sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==}
|
||||
@ -15002,7 +14995,7 @@ packages:
|
||||
engines: {node: '>=12.13.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
escape-string-regexp: 4.0.0
|
||||
is-wsl: 2.2.0
|
||||
lighthouse-logger: 1.4.2
|
||||
@ -15037,7 +15030,7 @@ packages:
|
||||
/chromium-edge-launcher@1.0.0:
|
||||
resolution: {integrity: sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==}
|
||||
dependencies:
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
escape-string-regexp: 4.0.0
|
||||
is-wsl: 2.2.0
|
||||
lighthouse-logger: 1.4.2
|
||||
@ -20183,7 +20176,7 @@ packages:
|
||||
'@jest/environment': 29.7.0
|
||||
'@jest/fake-timers': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
jest-mock: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
dev: false
|
||||
@ -20204,7 +20197,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
'@types/graceful-fs': 4.1.5
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
anymatch: 3.1.3
|
||||
fb-watchman: 2.0.2
|
||||
graceful-fs: 4.2.11
|
||||
@ -20262,7 +20255,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
jest-util: 29.7.0
|
||||
dev: false
|
||||
|
||||
@ -20276,7 +20269,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.9.0
|
||||
graceful-fs: 4.2.11
|
||||
@ -20307,7 +20300,7 @@ packages:
|
||||
resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@types/node': 20.11.19
|
||||
'@types/node': 20.8.0
|
||||
jest-util: 29.7.0
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
@ -28239,18 +28232,6 @@ packages:
|
||||
tslib: 2.1.0
|
||||
dev: true
|
||||
|
||||
/webext-additional-permissions@1.0.0:
|
||||
resolution: {integrity: sha512-QHMAah++muVoK/d+aYM56BY2DdpMAFMvW/dG28/+SdYJxgUsShsm3fOuwCPIiAIgsC8lsM52hZNJ1ROeii1lKg==}
|
||||
dependencies:
|
||||
'@types/chrome': 0.0.106
|
||||
dev: false
|
||||
|
||||
/webext-domain-permission-toggle@1.0.1:
|
||||
resolution: {integrity: sha512-vP3Io5KB+9YSlexDpSykcPKyu/U9pH07YGRIN1snwl92mvHy0aQlOmwYhAdfxLf4KKT7E1te1Bo0+ZvZJYFK2g==}
|
||||
dependencies:
|
||||
webext-additional-permissions: 1.0.0
|
||||
dev: false
|
||||
|
||||
/webextension-polyfill@0.6.0:
|
||||
resolution: {integrity: sha512-PlYwiX8e4bNZrEeBFxbFFsLtm0SMPxJliLTGdNCA0Bq2XkWrAn2ejUd+89vZm+8BnfFB1BclJyCz3iKsm2atNg==}
|
||||
dev: false
|
||||
|
||||
@ -2615,8 +2615,6 @@ PNPM,web-encoding,1.1.5,MIT,"",Approved
|
||||
PNPM,web-streams-polyfill,3.2.1,MIT,"",Approved
|
||||
PNPM,webcomponents.js,0.7.20,New BSD,"",Approved
|
||||
PNPM,webcrypto-core,1.7.5,MIT,"",Approved
|
||||
PNPM,webext-additional-permissions,1.0.0,MIT,"",Approved
|
||||
PNPM,webext-domain-permission-toggle,1.0.1,MIT,"",Approved
|
||||
PNPM,webextension-polyfill,0.6.0,Mozilla Public License 2.0,"",Approved
|
||||
PNPM,webidl-conversions,7.0.0,Simplified BSD,"",Approved
|
||||
PNPM,webpack,5.88.2,MIT,"",Approved
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user