Compare commits

...

No commits in common. "0.1.1" and "master" have entirely different histories.

91 changed files with 10993 additions and 13032 deletions

View File

@ -1,16 +0,0 @@
{
"presets": [[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"targets": {
"esmodules": true,
"ie": 11
}
}
]],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-proposal-object-rest-spread"
]
}

View File

@ -1,5 +1,8 @@
/public/bundle.js
/public/index.html
/npm
/cdn
**/*.html
node_modules
scripts/dev/*.js
*.html
**/libs/*.js
npm
docs
output
*.min.js

View File

@ -1,61 +1,66 @@
/*
* @Author: tackchen
* @Date: 2022-07-25 08:31:19
* @Description: Coding something
*/
module.exports = {
"env": {
"browser": true,
"es6": true,
"node": true,
"commonjs": true
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
'globals': {
'globalThis': true,
},
"parserOptions": {
"parser": "babel-eslint",
"ecmaVersion": 2018,
"ecmaFeatures": {
"arrowFunctions": true,
"classes": true,
"modules": true,
"defaultParams": true,
"experimentalObjectRestSpread": true
},
"sourceType": "module",
"parserOptions": {
"allowImportExportEverywhere": true
}
env: {
'browser': true,
'es6': true,
'node': true,
'commonjs': true,
},
"globals": {
"window": true,
'parserOptions': {
'sourceType': 'module' // ts 中使用 es 模块
},
"rules": {
"no-extend-native": 0,
"no-new": 0,
"no-useless-escape": 0,
"no-useless-constructor": 0,
"no-trailing-spaces": ["error", { "skipBlankLines": true }],
"indent": ["error", 4, {
"SwitchCase": 1
'rules': {
'no-var': 'error',
// 优先使用 interface 而不是 type
'@typescript-eslint/consistent-type-definitions': [
'error',
'interface'
],
'@typescript-eslint/no-unused-vars': 'error', // 使用 ts 未使用变量的规则 比如枚举类型在es中会报错
'no-extend-native': 0,
'no-new': 0,
'no-useless-escape': 0,
'no-useless-constructor': 0,
'no-trailing-spaces': ['error', {'skipBlankLines': true}],
'indent': ['error', 2, {
'SwitchCase': 1
}],
"space-infix-ops": ["error", {"int32Hint": false}],
"space-before-function-paren": ["error", {
"anonymous": "always",
"named": "always",
"asyncArrow": "always"
'space-infix-ops': ['error', {'int32Hint': false}],
'space-before-function-paren': ['error', {
'anonymous': 'always',
'named': 'always',
'asyncArrow': 'always'
}],
"semi": ["error", "always"],
"comma-dangle": 0,
"no-console": 0,
"no-debugger": 0,
"id-length": 0,
"eol-last": 0,
"object-curly-spacing": ["error", "never"],
"arrow-spacing": "error",
"no-multiple-empty-lines": "error",
"no-unused-vars": "error",
"spaced-comment": "error",
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"no-unreachable": "error",
"keyword-spacing": "error",
"space-before-blocks": "error",
"semi-spacing": "error",
"comma-spacing": "error",
"key-spacing": "error",
"no-undef": "error"
'semi': ['error', 'always'],
'comma-dangle': 0,
'no-console': 0,
'no-debugger': 0,
'id-length': 0,
'eol-last': 0,
'object-curly-spacing': ['error', 'never'],
'arrow-spacing': 'error',
'no-multiple-empty-lines': 'error',
'spaced-comment': 'error',
'quotes': ['error', 'single', {'allowTemplateLiterals': true}],
'no-unreachable': 'error',
'keyword-spacing': 'error',
'space-before-blocks': 'error',
'semi-spacing': 'error',
'comma-spacing': 'error',
'key-spacing': 'error',
'no-undef': 'error',
'prefer-const': ['error', {
'destructuring': 'any',
'ignoreReadBeforeAssign': false
}]
}
}
};

13
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: disable-devtool
ko_fi: theajack
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

35
.github/release-drafter.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
template: |
# What's Changed
### [Version Log](https://github.com/theajack/disable-devtool/blob/master/scripts/version.en.md)
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
categories:
# - title: 'Breaking'
# label: 'type: feat'
- title: 'New'
label: 'type: feat'
- title: 'Bug Fixes'
label: 'type: fix'
- title: 'Documentation'
label: 'type: docs'
- title: 'Other changes'
collapse-after: 5
version-resolver:
major:
labels:
- 'type: feat'
# minor:
# labels:
# - 'type: feat'
patch:
labels:
- 'type: fix'
- 'type: docs'
exclude-labels:
- 'skip-changelog'

29
.github/workflows/eb-docs.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Docs
on:
push:
tags:
- d*.*.*
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '16'
registry-url: https://registry.npmjs.org
- name: Build docs # build npm
run: npm run build:docs -- latest
- name: Pages # github pages
uses: JamesIves/github-pages-deploy-action@v4.3.0
with:
branch: gh-pages
folder: docs

84
.github/workflows/eb-release.yml vendored Normal file
View File

@ -0,0 +1,84 @@
name: Release
on:
push:
tags:
- v*.*.*
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '16'
registry-url: https://registry.npmjs.org
- name: Determine npm cache directory
id: npm-cache
run: |
echo "::set-output name=dir::$(npm config get cache)"
- name: Restore npm cache
uses: actions/cache@v3
with:
path: ${{ steps.npm-cache.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Npm Install
run: |
npm install pnpm@7.9.3 -g
pnpm install
- name: Version
id: version
run: |
tag=${GITHUB_REF/refs\/tags\//}
version=${tag#v}
echo "::set-output name=version::${version}"
- name: Build # build npm
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
run: |
npm run build -- ${{ steps.version.outputs.version }}
git config --global user.email "1506282385@qq.com"
git config --global user.name "theajack"
git checkout master
git add .
git commit -m "CI: push v${{ steps.version.outputs.version }}"
git push
- name: Build Docs
run: npm run build:docs -- ${{ steps.version.outputs.version }}
- name: Pages # github pages
uses: JamesIves/github-pages-deploy-action@v4.3.0
with:
branch: gh-pages
folder: docs
- name: Release # release
uses: release-drafter/release-drafter@v5
with:
version: ${{ steps.version.outputs.version }}
publish: true
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
- name: Publish # npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPMJS_TOKEN }}
run: |
cd npm
npm publish
- name: Purge # purge cdn
run: npm run purge

8
.gitignore vendored
View File

@ -1 +1,7 @@
/node_modules
node_modules
/output
.pnpm-debug.log
/npm
/docs
bundle.js
bundle.js.map

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
strict-peer-dependencies=false
registry=https://registry.npm.taobao.org/

29
.vscode/settings.json vendored
View File

@ -1,29 +0,0 @@
{
"editor.formatOnSave": false, // eslint
"eslint.validate": [
//.vue
"javascript",
"javascriptreact",
"html",
"vue",
{
"language": "html",
"autoFix": true
},
{
"language": "vue",
"autoFix": true
}
],
"search.exclude": {
"**/node_modules": true,
"**/cdn": true,
"**/npm": true
},
"eslint.autoFixOnSave": true,
"typescript.validate.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}

View File

@ -1,26 +1,73 @@
<h1><a href='https://www.github.com/theajack/disable-devtool'>Disable-devtool</a></h1>
<p align="center">
<a href='https://www.github.com/theajack/disable-devtool'>
<img src='https://shiyix.cn/images/disable-devtool3.png' width='240px'/>
</a>
</p>
<p align="center">
<a href="https://www.github.com/theajack/disable-devtool/stargazers" target="_black">
<img src="https://img.shields.io/github/stars/theajack/disable-devtool?logo=github" alt="stars" />
</a>
<a href="https://www.github.com/theajack/disable-devtool/network/members" target="_black">
<img src="https://img.shields.io/github/forks/theajack/disable-devtool?logo=github" alt="forks" />
</a>
<a href="https://www.npmjs.com/package/disable-devtool" target="_black">
<img src="https://img.shields.io/npm/v/disable-devtool?logo=npm" alt="version" />
</a>
<a href="https://www.npmjs.com/package/disable-devtool" target="_black">
<img src="https://img.shields.io/npm/dm/disable-devtool?color=%23ffca28&logo=npm" alt="downloads" />
</a>
<a href="https://www.jsdelivr.com/package/npm/disable-devtool" target="_black">
<img src="https://data.jsdelivr.com/v1/package/npm/disable-devtool/badge" alt="jsdelivr" />
</a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
</p>
<p align="center">
<a href="https://github.com/theajack" target="_black">
<img src="https://img.shields.io/badge/Author-%20theajack%20-7289da.svg?logo=github" alt="author" />
</a>
<a href="https://www.github.com/theajack/disable-devtool/blob/master/LICENSE" target="_black">
<img src="https://img.shields.io/github/license/theajack/disable-devtool?color=%232DCE89" alt="license" />
</a>
<a href="https://cdn.jsdelivr.net/npm/disable-devtool"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<!-- <a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a> -->
<img src="https://img.shields.io/badge/test-passed-44BB44" alt="test">
<img src="https://shiyix.cn/api2/util/badge/stat?c=Visitors-disabledevtool" alt="visitors">
</p>
<h2>🚀 一行代码搞定禁用web开发者工具 </h2>
**[English](https://github.com/theajack/disable-devtool/blob/master/README.md) | [在线试用](https://theajack.github.io/disable-devtool) | [更新日志](https://github.com/theajack/disable-devtool/blob/scripts/helper/version.md) | [Gitee](https://gitee.com/theajack/disable-devtool) | [留言板](https://theajack.github.io/message-board?app=disable-devtool) QQ交流群: 720626970**
----
<p align="">
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/github/stars/theajack/disable-devtool.svg?style=social" alt="star"></a>
<a href="https://theajack.gitee.io"><img src="https://img.shields.io/badge/author-theajack-blue.svg?style=social" alt="Author"></a>
</p>
开源维护不易,如果您有经济条件的话,可以捐赠给作者一杯咖啡
<p align="">
<a href="https://www.npmjs.com/package/disable-devtool"><img src="https://img.shields.io/npm/v/disable-devtool.svg" alt="Version"></a>
<a href="https://npmcharts.com/compare/disable-devtool?minimal=true"><img src="https://img.shields.io/npm/dm/disable-devtool.svg" alt="Downloads"></a>
<a href="https://cdn.jsdelivr.net/gh/theajack/disable-devtool/dist/disable-devtool.latest.min.js"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/disable-devtool.svg" alt="License"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a>
<a href="https://ko-fi.com/theajack">
<img src="https://img.shields.io/badge/Donate-Ko Fi-ff5f5f" alt="test">
</a>
<a href="https://paypal.me/tackchen">
<img src="https://img.shields.io/badge/Donate-PayPal-142c8e" alt="test">
</a>
<a href="https://shiyix.cn/images/wx-pay.png">
<img src="https://img.shields.io/badge/Donate-Wechat Pay-00c250" alt="test">
</a>
</p>
**[English](https://github.com/theajack/disable-devtool/blob/master/README.md) | [在线试用/文档](https://theajack.gitee.io/disable-devtool) | [更新日志](https://github.com/theajack/disable-devtool/blob/master/helper/version.md) | [Gitee](https://gitee.com/theajack/disable-devtool)**
----
## 0. 赞助商
<p align="center">
<a href="https://alinsjs.github.io/docs">
<img width="130" src="https://shiyix.cn/images/alins.png" alt="alins">
</a>
<p align="center"><a href="https://github.com/alinsjs/alins">Alins - 极致优雅的UI框架</a></p>
</p>
## 1. 快速使用
@ -31,26 +78,79 @@ npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
import DisableDevtool from 'disable-devtool';
disableDevtool();
DisableDevtool();
```
### 1.2 script属性配置
```html
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
```
或者通过版本引用:
```html
<!--使用指定版本-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x/disable-devtool.min.js'></script>
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x'></script>
<!--使用最新版本-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest/disable-devtool.min.js'></script>
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest'></script>
```
### 1.3 误触发问题定位帮助
----
<details>
<summary>如果您在使用过程中遇到问题,请点开我</summary>
因为设备、浏览器、运行环境众多,难免会有一些该库无法兼容的场景,此部分用于开发者自查问题,然后细节反馈到 issues以帮助我们定位和解决bug
#### 1.3.1 探测器被错误地触发
对于部分情况下,如果没有打开控制台但是页面没关闭了或是跳转走了的问题,原因是某个探测器被错误地触发了,请使用以下代码定位是哪个探测器被误触发了:
```js
DisableDevtool({
ondevtoolopen: (type) => {
const info = 'devtool opened!; type =' + type;
alert(info);
// 如果担心阻塞页面 请使用 console.warn(info); 并打开控制台查看
},
})
```
上述代码在使用脚本引用时需要这样使用
```html
<script src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
<script>
DisableDevtool({
ondevtoolopen: (type) => {
const info = 'devtool opened!; type =' + type;
alert(info); // 如果担心阻塞页面 请使用 console.warn(info); 并打开控制台查看
},
})
</script>
```
#### 1.3.2 探测器没有被触发
当通过任意方式打开了devtool但是页面没有正确的关闭或者跳转时首先请尝试打印以下内容看看探测器是否在正常工作
```js
console.log(DisableDevtool.isRunning);
```
如果返回的是true那么这就是一个不兼容的问题原因是所有探测器都没有被触发这种情况是比较棘手的目前来看没有通用的定位方法
请提交一个issue尽可能详细地提供您使用的浏览器版本、设备型号及版本、运行环境最好是有截图或者演示地址我们后续会进行相应的问题排查
</details>
----
## 2.功能
disable-devtool 可以禁用所有一切可以进入开发者工具的方法,防止通过开发者工具进行的 ‘代码搬运’
@ -58,19 +158,26 @@ disable-devtool 可以禁用所有一切可以进入开发者工具的方法,
该库有以下特性:
1. 支持可配置是否禁用右键菜单
2. 禁用 f12 和 ctrl+shift+i 快捷键
2. 禁用 f12 和 ctrl+shift+i 快捷键
3. 支持识别从浏览器菜单栏打开开发者工具并关闭当前页面
4. 开发者可以绕过禁用 (url参数使用tk配合md5加密)
5. 支持几乎所有浏览器IE,360,qq浏览器,FireFox,Chrome,Edge...
6. 高度可配置
7. 使用极简、体积小巧 (仅7kb)
8. 支持npm引用和script标签引用(属性配置)
9. 识别真移动端与浏览器开发者工具设置插件伪造的移动端,为移动端节省性能
5. 多种监测模式支持几乎所有浏览器IE,360,qq浏览器,FireFox,Chrome,Edge...
6. 高度可配置、使用极简、体积小巧
7. 支持npm引用和script标签引用(属性配置)
8. 识别真移动端与浏览器开发者工具设置插件伪造的移动端,为移动端节省性能
9. 支持识别开发者工具关闭事件
10. 支持可配置是否禁用选择、复制、剪切、粘贴功能
11. 支持识别 eruda 和 vconsole 调试工具
12. 支持挂起和恢复探测器工作
13. 支持配置ignore属性用以自定义控制是否启用探测器
14. 支持配置iframe中所有父页面的开发者工具禁用
## 3. 使用
### 3.1 npm使用时的配置参数
推荐使用这种方式安装使用使用script脚本可以被代理单独拦截掉从而无法执行
安装 disable-devtool
```
@ -78,23 +185,60 @@ npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
import DisableDevtool from 'disable-devtool';
disableDevtool(options);
DisableDevtool(options);
```
#### 3.1.1 返回值
返回值 DisableDevtool 的返回值为如下类型
```ts
interface IDDResult {
success: boolean; // 表示是否正常启用
reason: string; // 未正常启用的原因
}
```
#### 3.1.2 参数
options中的参数与说明如下
```ts
declare interface optionStatic {
interface IConfig {
md5?: string; // 绕过禁用的md5值详情见3.2,默认不启用绕过禁用
url?: string; // 关闭页面失败时的跳转页面默认值为localhost
tkName?: string; // 绕过禁用时的url参数名称默认为 ddtk
ondevtoolopen?(): void; // 开发者面板打开的回调启用时url参数无效
ondevtoolopen?(type: DetectorType, next: Function): void; // 开发者面板打开的回调启用时url参数无效type 为监测模式详见3.5 next函数是关闭当前窗口
ondevtoolclose?(): void; // 开发者面板关闭的回调
interval?: number; // 定时器的时间间隔 默认200ms
disableMenu?: boolean; // 是否禁用右键菜单 默认为true
stopIntervalTime?: number; // 在移动端时取消监视的等待时长
clearIntervalWhenDevOpenTrigger?: boolean; // 是否在触发之后停止监控 默认为false 在使用ondevtoolclose时该参数无效
detectors?: Array<DetectorType>; // 启用的检测器 检测器详情见 3.5 默认为全部,建议使用全部
clearLog?: boolean; // 是否每次都清除log
disableSelect?: boolean; // 是否禁用选择文本 默认为false
disableCopy?: boolean; // 是否禁用复制 默认为false
disableCut?: boolean; // 是否禁用剪切 默认为false
disablePaste: boolean; // 是否禁用粘贴 默认为false
ignore?: (string|RegExp)[] | null | (()=>boolean); // 某些情况忽略禁用
disableIframeParents?: boolean; // iframe中是否禁用所有父窗口
timeOutUrl?: string; // 关闭页面超时跳转的url;
rewriteHTML: string; // 检测到打开之后重写页面
}
enum DetectorType {
Unknown = -1,
RegToString = 0, // 根据正则检测
DefineId, // 根据dom id检测
Size, // 根据窗口尺寸检测
DateToString, // 根据Date.toString 检测
FuncToString, // 根据Function.toString 检测
Debugger, // 根据断点检测仅在ios chrome 真机情况下有效
Performance, // 根据log大数据性能检测
DebugLib, // 检测第三方调试工具 eruda 和 vconsole
};
```
### 3.2 md5 与 tk 绕过禁用
@ -108,7 +252,7 @@ declare interface optionStatic {
disableDevtool对象暴露了 md5 方法,可供开发者加密时使用:
```js
disableDevtool.md5('xxx');
DisableDevtool.md5('xxx');
```
### 3.3 script使用属性配置
@ -116,12 +260,18 @@ disableDevtool.md5('xxx');
```html
<script
disable-devtool-auto
src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'
src='https://cdn.jsdelivr.net/npm/disable-devtool'
md5='xxx'
url='xxx'
tk-name='xxx'
interval='xxx'
disable-menu='xxx'
detectors='xxx'
clear-log='true'
disable-select='true'
disable-copy='true'
disable-cut='true'
disable-paste='true'
></script>
```
@ -130,14 +280,102 @@ disableDevtool.md5('xxx');
1. 如希望自动禁用,属性配置时必须要带上 `disable-devtool-auto` 属性
2. 属性配置都是可选的字段与3.1中一致,区别是将驼峰形式改成横线分割
3. 该script标签建议放在body最底部
4. detectors 需要使用空格分割,如 detectors='1 2 3'
### 3.4 script不使用属性配置
```html
<script src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
<script>
DisableDevtool({
// 参数与3.1中一致
})
</script>
```
### 3.5 监测模式
Disable-Devtool 有以下几种监测模式, DisableDevtool.DetectorType 为所有的监测模式枚举
```ts
enum DetectorType {
Unknown = -1,
RegToString = 0, // 根据正则检测
DefineId, // 根据dom id检测
Size, // 根据窗口尺寸检测 // 0.3.5版本后该探测器默认不启用
DateToString, // 根据Date.toString 检测
FuncToString, // 根据Function.toString 检测
Debugger, // 根据断点检测仅在ios chrome 真机情况下有效
Performance, // 根据log大数据性能检测
DebugLib, // 检测第三方调试工具
};
```
ondevtoolopen 事件的回调参数就是被触发的监测模式
可以在 ondevtoolopen 里执行业务逻辑,比如做数据上报、用户行为分析等
```ts
DisableDevtool({
ondevtoolopen(type, next){
alert('Devtool opened with type:' + type);
next();
}
});
```
### 3.6 其他 API
#### 3.6.1 isRunning
用于获取 DisableDevtool 是否正在运行中 (挂起或忽略状态也视为运行中,因为可以动态开启)
```js
DisableDevtool.isRunning;
```
#### 3.6.2 isSuspend
用于获取或设置 DisableDevtool 是否被挂起 (挂起状态所有的禁用都将暂时失效)
```js
DisableDevtool.isSuspend = true;
DisableDevtool.isSuspend = false;
```
#### 3.6.3 config.ignore
ignore 用于自定义某些忽略的场景
1. 传入数组
传入数组是支持 字符串和正则表达式,表示匹配链接中是否含有传入的内容,使用如下
```js
DisableDevtool({
ignore: [
'/user/login', // 当链接中含有该内容时禁用暂时被忽略
/\/user\/[0-9]{6}/, // 当链接匹配该正则时禁用暂时被忽略
]
});
```
2. 传入函数
传入函数表示自定义判断条件返回一个bool类型使用如下
```js
DisableDevtool({
ignore: () => {
return userType === 'admin'; // 当是管理员时忽略禁用
}
});
```
#### 3.6.4 version
用于获取 DisableDevtool 版本号
```js
DisableDevtool.version;
```

338
README.md
View File

@ -1,25 +1,70 @@
<h1><a href='https://www.github.com/theajack/disable-devtool'>Disable-devtool</a></h1>
<h2>🚀 Disable web developer tools with one line </h2>
<p align="center">
<a href='https://www.github.com/theajack/disable-devtool'>
<img src='https://shiyix.cn/images/disable-devtool3.png' width='240px'/>
</a>
</p>
<p align="center">
<a href="https://www.github.com/theajack/disable-devtool/stargazers" target="_black">
<img src="https://img.shields.io/github/stars/theajack/disable-devtool?logo=github" alt="stars" />
</a>
<a href="https://www.github.com/theajack/disable-devtool/network/members" target="_black">
<img src="https://img.shields.io/github/forks/theajack/disable-devtool?logo=github" alt="forks" />
</a>
<a href="https://www.npmjs.com/package/disable-devtool" target="_black">
<img src="https://img.shields.io/npm/v/disable-devtool?logo=npm" alt="version" />
</a>
<a href="https://www.npmjs.com/package/disable-devtool" target="_black">
<img src="https://img.shields.io/npm/dm/disable-devtool?color=%23ffca28&logo=npm" alt="downloads" />
</a>
<a href="https://www.jsdelivr.com/package/npm/disable-devtool" target="_black">
<img src="https://data.jsdelivr.com/v1/package/npm/disable-devtool/badge" alt="jsdelivr" />
</a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
</p>
<p align="center">
<a href="https://github.com/theajack" target="_black">
<img src="https://img.shields.io/badge/Author-%20theajack%20-7289da.svg?logo=github" alt="author" />
</a>
<a href="https://www.github.com/theajack/disable-devtool/blob/master/LICENSE" target="_black">
<img src="https://img.shields.io/github/license/theajack/disable-devtool?color=%232DCE89" alt="license" />
</a>
<a href="https://cdn.jsdelivr.net/npm/disable-devtool"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<!-- <a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a> -->
<img src="https://img.shields.io/badge/test-passed-44BB44" alt="test">
<img src="https://shiyix.cn/api2/util/badge/stat?c=Visitors-disabledevtool" alt="visitors">
</p>
<h2>🚀 One line of code to disable web developer tools </h2>
**[中文](https://github.com/theajack/disable-devtool/blob/master/README.cn.md) | [Online Trial](https://theajack.github.io/disable-devtool) | [Changelog](https://github.com/theajack/disable-devtool/blob/master/scripts/version.md) | [Gitee](https://gitee.com/theajack/disable-devtool) | [Message Board](https://theajack.github.io/message-board?app=disable-devtool) QQ Group: 720626970**
----
<p align="">
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/github/stars/theajack/disable-devtool.svg?style=social" alt="star"></a>
<a href="https://theajack.gitee.io"><img src="https://img.shields.io/badge/author-theajack-blue.svg?style=social" alt="Author"></a>
</p>
<p align="">
<a href="https://www.npmjs.com/package/disable-devtool"><img src="https://img.shields.io/npm/v/disable-devtool.svg" alt="Version"></a>
<a href="https://npmcharts.com/compare/disable-devtool?minimal=true"><img src="https://img.shields.io/npm/dm/disable-devtool.svg" alt="Downloads"></a>
<a href="https://cdn.jsdelivr.net/gh/theajack/disable-devtool/dist/disable-devtool.latest.min.js"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/disable-devtool.svg" alt="License"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a>
<a href="https://ko-fi.com/theajack">
<img src="https://img.shields.io/badge/Donate-Ko Fi-ff5f5f" alt="test">
</a>
<a href="https://paypal.me/tackchen">
<img src="https://img.shields.io/badge/Donate-PayPal-142c8e" alt="test">
</a>
<a href="https://shiyix.cn/images/wx-pay.png">
<img src="https://img.shields.io/badge/Donate-Wechat Pay-00c250" alt="test">
</a>
</p>
**[中文](https://github.com/theajack/disable-devtool/blob/master/README.cn.md) | [online trial/document](https://theajack.gitee.io/disable-devtool) | [Version Log](https://github.com/theajack/disable-devtool/blob/master/helper/version.md) | [Gitee](https://gitee.com/theajack/disable-devtool)**
----
## 0. Sponsor
<p align="center">
<a href="https://alinsjs.github.io/docs">
<img width="130" src="https://shiyix.cn/images/alins.png" alt="alins">
</a>
<p align="center"><a href="https://github.com/alinsjs/alins">Alins - The Most Elegant JS FrameWork</a></p>
</p>
## 1. Quick use
@ -30,84 +75,181 @@ npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
import DisableDevtool from 'disable-devtool';
disableDevtool();
DisableDevtool();
```
### 1.2 script attribute configuration
```html
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
```
Or use cdn with version:
Or cite by version:
```html
<!--Use a specific version-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x/disable-devtool.min.js'></script>
<!--Use the specified version-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x'></script>
<!--Use latest version-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest/disable-devtool.min.js'></script>
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest'></script>
```
### 1.3 False trigger problem location help
----
<details>
<summary>If you have problems during use, please click on me</summary>
Because there are many devices, browsers, and operating environments, it is inevitable that there will be some scenarios where the library is incompatible, and this part is used for developers to check the problem by themselves, and then feedback the details to issues to help us locate and solve bugs
#### 1.3.1 The probe was triggered incorrectly
In some cases, if the console is not opened but the page does not close or the jump is away, because a probe is triggered by error, use the following code to locate which probe was triggered by mistake:
```js
DisableDevtool({
ondevtoolopen: (type) => {
const info = 'devtool opened!; type =' + type;
alert(info);
// If you are worried about blocking the page, use console.warn(info); and open the console to view
},
})
```
The above code needs to be used this when using script references
```html
<script src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
<script>
DisableDevtool({
ondevtoolopen: (type) => {
const info = 'devtool opened!; type =' + type;
alert(info); // If you are worried about blocking the page, use console.warn(info); and open the console to view
},
})
</script>
```
#### 1.3.2 The probe is not triggered
When devtool is opened in any way, but the page does not close or jump correctly, first try printing the following to see if the detector is working properly
```js
console.log(DisableDevtool.isRunning);
```
If it returns true, then this is an incompatibility problem because none of the probes are triggered, which is tricky, and there is currently no universal way to locate it
Please submit an issue, as detailed as possible with the browser version, device model and version, operating environment, preferably a screenshot or demo address, we will troubleshoot the corresponding problem later
</details>
----
## 2. Function
disable-devtool can disable all the methods that can enter the developer tools to prevent code handling through the developer tools
disable-devtool disables all access to the devtools, preventing 'code porting' via the devtools
The library has the following features:
1. Support configurable whether to disable the right-click menu
2. Disable f12 and ctrl+shift+i shortcuts
3. Support recognition to open the developer tools from the browser menu bar and close the current page
4. Developers can bypass the disablement (use tk and md5 encryption for url parameters)
5. Support almost all browsers (IE,360,qq browser,FireFox,Chrome,Edge...)
6. Highly configurable
7. Minimal use, small size (only 7kb)
8. Support npm reference and script tag reference (attribute configuration)
9. Identify the real mobile terminal and browser developer tool settings plug-in forged mobile terminal, saving performance for the mobile terminal
2. Disable shortcut keys such as f12 and ctrl+shift+i
3. Support recognition to open developer tools from browser menu bar and close the current page
4. Developers can bypass the disable (url parameters are encrypted with tk and md5)
5. Multiple monitoring modes, support almost all browsers (IE, 360, qq browser, FireFox, Chrome, Edge...)
6. Highly configurable, minimalist to use, compact
7. Support npm reference and script tag reference (property configuration)
8. Identify the real mobile terminal and the browser developer tool to set the plug-in forged mobile terminal to save performance for the mobile terminal
9. Support for identifying developer tools close events
10. Support configurable whether to disable selection, copy, cut, paste function
11. Support to identify eruda and vconsole debugging tools
12. Support suspending and resuming probe work
13. Support configuring ignore attributes to customize whether to enable probes
14. Support for configuring all parent pages in iframes to be disabled
## 3. Use
### 3.1 Configuration parameters when using npm
Install disable-devtool
It is recommended to use this method of installation and use, and the script script can be intercepted by the agent separately and cannot be executed
install disable-devtool
```
npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
import DisableDevtool from 'disable-devtool';
disableDevtool(options);
DisableDevtool(options);
```
#### 3.1.1 Return value
Return value DisableDevtool The return value is of the following type
```ts
interface IDDResult {
success: boolean; Indicates whether it is enabled normally
reason: string; The reason why it was not properly enabled
}
```
#### 3.1.2 parameters
The parameters and descriptions in options are as follows:
```ts
declare interface optionStatic {
md5?: string; // Bypass the disabled md5 value, see 3.2 for details, the bypass disable is not enabled by default
url?: string; // Jump to the page when closing the page fails, the default value is localhost
tkName?: string; // Bypass the url parameter name when disabled, the default is ddtk
ondevtoolopen?(): void; // Callback for opening the developer panel, the url parameter is invalid when enabled
interval?: number; // Timer interval is 200ms by default
disableMenu?: boolean; // Whether to disable the right-click menu The default is true
declare interface IConfig {
md5?: string; // bypass disabled md5 value, see 3.2 for details, bypass disabled by default
url?: string; // Jump page when closing the page fails, the default value is localhost
tkName?: string; // bypass url parameter name when disabled, default is ddtk
ondevtoolopen?(type: DetectorType, next: Function): void; // The callback for opening the developer panel, the url parameter is invalid when enabled, the type is monitoring mode, see 3.5 for details, the next function is to close the current window
ondevtoolclose?(): void; // callback for developer panel close
interval?: number; // timer interval default 200ms
disableMenu?: boolean; // Whether to disable the right-click menu Default is true
stopIntervalTime?: number; // Waiting time to cancel monitoring on mobile
clearIntervalWhenDevOpenTrigger?: boolean; // Whether to stop monitoring after triggering the default is false, this parameter is invalid when using ondevtoolclose
detectors?: Array<DetectorType>; // Enabled detectors See 3.5 for details of detectors. The default is all, it is recommended to use all
clearLog?: boolean; // Whether to clear the log every time
disableSelect?: boolean; // Whether to disable selection text Default is false
disableCopy?: boolean; // Whether to disable copying, default is false
disableCut?: boolean; // Whether to disable cutting, default is false
disablePaste: boolean; // Whether to disable paste, default is false
ignore?: (string| RegExp)[] | null | (()=>boolean); // Some cases ignore the disablement
disableIframeParents?: boolean; // Whether all parent windows are disabled in the iframe
timeOutUrl?: string; // Turn off URLs that page timeouts forward towards
rewriteHTML?: string; // Detecting the rewriting page after opening
}
enum DetectorType {
Unknown = -1,
RegToString = 0, // Check according to regular
DefineId, // detect based on dom id
Size, // Detect based on window size // After version 0.3.5, this probe is not enabled by default
DateToString, // check against Date.toString
FuncToString, // check according to Function.toString
Debugger, // According to breakpoint detection, it is only valid in the case of ios chrome real machine
Performance, // Performance detection based on log big data
DebugLib, // Detect third-party debugging tools eruda and vconsole
};
```
### 3.2 md5 and tk bypass disable
### 3.2 md5 and tk bypass disabled
The combination of key and md5 in the library allows developers to bypass the disabling online.
The way in which the key is used in conjunction with md5 in this library allows developers to bypass the ban online.
The process is as follows:
First specify a key a (the value should not be recorded in the code), use md5 encryption to obtain a value b, and pass in b as the md5 parameter. Developers only need to bring the url parameter ddtk=a when accessing the url. Bypass disabled.
First specify a key a (the value should not be recorded in the code), use md5 encryption to obtain a value b, and pass in b as the md5 parameter. When accessing the url, the developer only needs to bring the url parameter ddtk=a, then you can Bypass disable.
The disableDevtool object exposes the md5 method, which can be used by developers when encrypting:
```js
disableDevtool.md5('xxx');
DisableDevtool.md5('xxx');
```
### 3.3 script uses attribute configuration
@ -115,28 +257,122 @@ disableDevtool.md5('xxx');
```html
<script
disable-devtool-auto
src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'
src='https://cdn.jsdelivr.net/npm/disable-devtool'
md5='xxx'
url='xxx'
tk-name='xxx'
interval='xxx'
disable-menu='xxx'
detectors='xxx'
clear-log='true'
disable-select='true'
disable-copy='true'
disable-cut='true'
disable-paste='true'
></script>
```
Note:
1. If you want to automatically disable,you must bring the `disable-devtool-auto` attribute when configuring attributes
2. Attribute configuration is optional, the fields are the same as in 3.1, the difference is that the hump form is changed to horizontal line division
1. If you want to disable it automatically, you must include the `disable-devtool-auto` property when configuring the property
2. The attribute configuration is optional, and the fields are the same as in 3.1, the difference is that the hump form is changed to a horizontal line.
3. The script tag is recommended to be placed at the bottom of the body
4. Detectors need to be separated by spaces, such as detectors='1 2 3'
### 3.4 script does not use attribute configuration
```html
<script src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
<script>
DisableDevtool({
// The parameters are the same as in 3.1
})
</script>
```
```
### 3.5 Monitoring Mode
Disable-Devtool has the following monitoring modes, DisableDevtool.DetectorType enumerates all monitoring modes
```ts
enum DetectorType {
Unknown = -1,
RegToString = 0, // Check according to regular
DefineId, // detect based on dom id
Size, // Detect based on window size
DateToString, // check against Date.toString
FuncToString, // check according to Function.toString
Debugger, // According to breakpoint detection, it is only valid in the case of ios chrome real machine
Performance, // Performance detection based on log big data
DebugLib, // Detect third-party debugging tools
};
```
The callback parameter of the ondevtoolopen event is the triggered monitoring mode
You can execute business logic in OndevtoolOpen, such as data reporting, user behavior analysis, etc
```ts
DisableDevtool({
ondevtoolopen(type, next){
alert('Devtool opened with type:' + type);
next();
}
});
```
### 3.6 Additional APIs
#### 3.6.1 isRunning
Used to get whether DisableDevtool is running (the pending or ignore state is also considered running because it can be turned on dynamically)
```js
DisableDevtool.isRunning;
```
#### 3.6.2 isSuspend
Used to get or set whether DisableDevtool is suspended (suspended state, all disabled will be temporarily disabled)
```js
DisableDevtool.isSuspend = true;
DisableDevtool.isSuspend = false;
```
#### 3.6.3 config.ignore
ignore is used to customize certain ignored scenarios
1. Pass in the array
The incoming array is supported by strings and regular expressions that indicate whether the matching link contains the incoming content, using the following
```js
DisableDevtool({
ignore: [
'/user/login', // Disabled is temporarily ignored when the link contains this content
/\/user\/[0-9]{6}/, // When a link matches that regular, disabling is temporarily ignored
]
});
```
2. Pass in the function
The passing function represents a custom judgment condition and returns a bool type, as follows
```js
DisableDevtool({
ignore: () => {
return userType === 'admin'; // Disable is ignored when you are an administrator
}
});
```
#### 3.6.4 version
Get DisableDevtool version
```js
DisableDevtool.version;
```

16
babel.config.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'entry',
targets: {
esmodules: true,
ie: 11,
},
},
],
'@babel/preset-typescript',
],
};

View File

@ -1,10 +0,0 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert'
]],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never']
}
};

5
dist/disable-devtool.0.3.7.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,30 +0,0 @@
const gulp = require('gulp');
const pkg = require('../package.json');
const util = require('./util');
function main () {
copyPkg();
copyFiles();
}
function copyPkg () {
let npmPkg = util.pick({
target: pkg,
attrs: [
'name', 'version', 'description', 'main', 'unpkg', 'jsdelivr',
'typings', 'repository', 'keywords', 'author', 'license', 'bugs', 'homepage'
]
});
util.write('npm/package.json', JSON.stringify(npmPkg, null, 4));
}
function copyFiles () {
gulp.src(['README.md', 'README.cn.md', 'LICENSE', 'src/index.d.ts'], {
allowEmpty: true
})
.pipe(gulp.dest('npm'));
}
main();

View File

@ -1,8 +0,0 @@
const pkg = require('../package.json');
const util = require('./util');
function main () {
util.write('src/version.js', `export default '${pkg.version}';`);
}
main();

View File

@ -1,13 +0,0 @@
const pkg = require('../package.json');
const util = require('./util');
function modIndexHtmlVersion () {
util.read('index.html', (html) => {
let res = html.match(new RegExp(`https://cdn.jsdelivr.net/npm/disable-devtool@.*/disable-devtool.min.js#use`));
if (res) {
util.write('index.html', html.replace(res[0], `https://cdn.jsdelivr.net/npm/disable-devtool@${pkg.version}/disable-devtool.min.js#use`));
}
});
}
modIndexHtmlVersion();

View File

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Disable Devtool Demo</title>
</head>
<body>
<script disable-devtool-auto
md5='d4de605ccb923b7e876b3218a1474653'
tk-name='tk'
src="../npm/disable-devtool.min.js"></script>
</body>
</html>

View File

@ -1,28 +0,0 @@
let fs = require('fs');
module.exports = {
read: function (file, cb) {
fs.readFile(file, 'utf8', (err, code) => {
if (err) throw err;
cb(code);
});
},
write: function (file, txt, cb) {
fs.writeFile(file, txt, 'utf8', (err) => {
if (err) throw err;
if (cb)cb();
});
},
pick: function ({data = {}, target, attrs}) {
if (!attrs) {
attrs = Object.keys(target);
}
attrs.forEach(name => {
if (typeof target[name] !== 'undefined')
data[name] = target[name];
});
return data;
}
};

View File

@ -1,41 +0,0 @@
# Version Log:
## 0.0.1
1. 支持可配置是否禁用右键菜单
2. 禁用 f12 和 ctrl+shift+i 快捷键
3. 支持识别从浏览器菜单栏打开开发者工具并关闭当前页面
4. 开发者可以绕过禁用 (url参数使用tk配合md5加密)
5. 支持几乎所有浏览器
6. 高度可配置
7. 使用极简、体积小巧 (仅7kb)
8. 支持npm引用和script标签引用(属性配置)
## 0.0.2
1. 解决cdn文件无效的bug
## 0.0.3
1. 解决alert等原生方法会影响debug计时导致
2. 解决页面且后台会影响debug计时导致
3. 兼容iedisableMenu参数在ie下无效因为ie下右键会阻塞主进程且无法监听
4. 增加config.stopIntervalTime 表示在移动端时取消监视的等待时长
5. 优化判断开发者工具打开的逻辑
## 0.0.4
1. 修改 webpack 打包配置
## 0.0.5
1. 优化onDevToolOpen事件触发逻辑
## 0.0.6
1. 对于标签属性配置移除id='disable-devtool' 条件,使用 disable-devtool-auto属性
2. 修改readme
## 0.1.0
1. 修复firefox和qq浏览器下无效的问题
2. 启用 disableMenu 配置
3. 去除内部debug逻辑
4. 增加默认跳转的404页面
## 0.1.1
1. 增加history.back 之后跳转默认页的延迟
2. 优化ondeltoolopen 逻辑

View File

@ -1,203 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>一行代码搞定禁用web开发者工具</title>
<style>
code{
white-space: pre;
font-family: Consolas, "Courier New", monospace;
color: #fff;
background-color: #444;
display: block;
overflow-x: auto;
border-radius: 5px;
padding: 10px;
}
body{
max-width: 1000px;
margin: 0 auto;
padding: 0 20px;
}
</style>
</head>
<body>
<h1><a style='color:#222' href='https://www.github.com/theajack/disable-devtool'>Disable-devtool</a></h1>
<h2>🚀 Disable web developer tools with one line </h2>
<p>
<a href="https://www.github.com/theajack/disable-devtool"><img
src="https://img.shields.io/github/stars/theajack/disable-devtool.svg?style=social" alt="star"></a>
<a href="https://theajack.gitee.io"><img
src="https://img.shields.io/badge/author-theajack-blue.svg?style=social" alt="Author"></a>
</p>
<p>
<a href="https://www.npmjs.com/package/disable-devtool"><img
src="https://img.shields.io/npm/v/disable-devtool.svg" alt="Version"></a>
<a href="https://npmcharts.com/compare/disable-devtool?minimal=true"><img
src="https://img.shields.io/npm/dm/disable-devtool.svg" alt="Downloads"></a>
<a href="https://cdn.jsdelivr.net/gh/theajack/disable-devtool/dist/disable-devtool.latest.min.js"><img
src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/blob/master/LICENSE"><img
src="https://img.shields.io/npm/l/disable-devtool.svg" alt="License"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img
src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<a href="https://github.com/theajack/disable-devtool/issues"><img
src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
<a href="https://www.github.com/theajack/disable-devtool"><img
src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a>
</p>
<p><strong><a href="https://github.com/theajack/disable-devtool/blob/master/README.cn.md">中文</a> | <a
href="https://theajack.gitee.io/disable-devtool">online trial/document</a> | <a
href="https://gitee.com/theajack/disable-devtool">Gitee</a></strong></p>
<p>
Now that the devtool on this page has been disabled, use the <a href='https://theajack.gitee.io/disable-devtool?ddtk=dd'>?ddtk=dd</a> url parameter to un-disable (ddtk value is configurable)
</p>
<h2>1. Quick use</h2>
<h3>1.1 npm reference</h3>
<p><code>npm i disable-devtool</code></p>
<p>
<code>import disableDevtool from&#39;disable-devtool&#39;;
disableDevtool();</code>
</p>
<h3>1.2 script attribute configuration</h3>
<p><code>&lt;script disable-devtool-auto src=&#39;https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js&#39;&gt;&lt;/script&gt;</code></p>
<p>Or use cdn with version:</p>
<p><code>&lt;!--Use a specific version-->
&lt;script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x/disable-devtool.min.js'>&lt;/script>
&lt;!--Use latest version-->
&lt;script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest/disable-devtool.min.js'>&lt;/script></code></p>
<h2>2. Function</h2>
<p>disable-devtool can disable all the methods that can enter the developer tools to prevent code handling through
the developer tools</p>
<p>The library has the following features:</p>
<ol>
<li>Support configurable whether to disable the right-click menu</li>
<li>Disable f12 and ctrl+shift+i shortcuts</li>
<li>Support recognition to open the developer tools from the browser menu bar and close the current page</li>
<li>Developers can bypass the disablement (use tk and md5 encryption for url parameters)</li>
<li>Support almost all browsers (IE,360,qq browser,FireFox,Chrome,Edge...)</li>
<li>Highly configurable</li>
<li>Minimal use, small size (only 7kb)</li>
<li>Support npm reference and script tag reference (attribute configuration)</li>
<li>Identify the real mobile terminal and browser developer tool settings plug-in forged mobile terminal, saving performance for the mobile terminal</li>
</ol>
<h2>3. Use</h2>
<h3>3.1 Configuration parameters when using npm</h3>
<p>Install disable-devtool</p>
<p><code>npm i disable-devtool</code></p>
<p><code>import disableDevtool from&#39;disable-devtool&#39;;
disableDevtool(options);</code></p>
<p>The parameters and descriptions in options are as follows:</p>
<p><code>declare interface optionStatic {
md5?: string; // Bypass the disabled md5 value, see 3.2 for details, the bypass disable is not enabled by default
url?: string; // Jump to the page when closing the page fails, the default value is localhost
tkName?: string; // Bypass the url parameter name when disabled, the default is ddtk
ondevtoolopen?(): void; // Callback for opening the developer panel, the url parameter is invalid when enabled
interval?: number; // Timer interval is 200ms by default
disableMenu?: boolean; // Whether to disable the right-click menu The default is true
stopIntervalTime?: number; // Waiting time to cancel monitoring on mobile
}</code></p>
<h3>3.2 md5 and tk bypass disable</h3>
<p>The combination of key and md5 in the library allows developers to bypass the disabling online.</p>
<p>The process is as follows:</p>
<p>First specify a key a (the value should not be recorded in the code), use md5 encryption to obtain a value b, and
pass in b as the md5 parameter. Developers only need to bring the url parameter ddtk=a when accessing the url.
Bypass disabled.</p>
<p>The disableDevtool object exposes the md5 method, which can be used by developers when encrypting:</p>
<p><code>disableDevtool.md5(&#39;xxx&#39;);</code></p>
<div>
TOOL:
<input type="text" id='md5_key' placeholder="Enter a key">
<button onclick="generateMd5()">Generate md5</button>
<span id='md5_value'></span>
</div>
<h3>3.2 script uses attribute configuration</h3>
<p><code>&lt;script
disable-devtool-auto
src=&#39;https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js&#39;
md5=&#39;xxx&#39;
url=&#39;xxx&#39;
tk-name=&#39;xxx&#39;
interval=&#39;xxx&#39;
disable-menu=&#39;xxx&#39;>
&lt;/script&gt;</code></p>
</blockquote>
<p>Note:<br>
1. You must bring the <strong>disable-devtool-auto</strong> attribute when configuring attributes<br>
2.Attribute configuration is optional, the fields are the same as in 3.1, the difference is that the hump form is
changed to horizontal line division <br>
3. The script tag is recommended to be placed at the bottom of the body</p>
<h3>3.3 script does not use attribute configuration</h3>
<p><code>&lt;script src=&#39;https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js&#39;&gt;&lt;/script&gt;
&lt;script&gt;
DisableDevtool({
// The parameters are the same as in 3.1
})
&lt;/script&gt;</code></p>
<script
disable-devtool-auto
md5='1aabac6d068eef6a7bad3fdf50a05cc8'
src='https://cdn.jsdelivr.net/npm/disable-devtool@0.1.1/disable-devtool.min.js#use'
></script>
<!-- <script disable-devtool-auto md5='1aabac6d068eef6a7bad3fdf50a05cc8' src='./npm/disable-devtool.min.js'></script> -->
<script>
function setText(text){
document.getElementById('md5_value').innerText = text;
}
function generateMd5(){
if(!window.DisableDevtool){
alert('DisableDevtool not ready');
return;
}
let key = document.getElementById('md5_key').value;
if(!key){
alert('Key is empty');
return;
}
setText(DisableDevtool.md5(key));
}
</script>
</body>
</html>

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2019 - present
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,143 +0,0 @@
<h1><a href='https://www.github.com/theajack/disable-devtool'>Disable-devtool</a></h1>
<h2>🚀 一行代码搞定禁用web开发者工具 </h2>
----
<p align="">
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/github/stars/theajack/disable-devtool.svg?style=social" alt="star"></a>
<a href="https://theajack.gitee.io"><img src="https://img.shields.io/badge/author-theajack-blue.svg?style=social" alt="Author"></a>
</p>
<p align="">
<a href="https://www.npmjs.com/package/disable-devtool"><img src="https://img.shields.io/npm/v/disable-devtool.svg" alt="Version"></a>
<a href="https://npmcharts.com/compare/disable-devtool?minimal=true"><img src="https://img.shields.io/npm/dm/disable-devtool.svg" alt="Downloads"></a>
<a href="https://cdn.jsdelivr.net/gh/theajack/disable-devtool/dist/disable-devtool.latest.min.js"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/disable-devtool.svg" alt="License"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a>
</p>
**[English](https://github.com/theajack/disable-devtool/blob/master/README.md) | [在线试用/文档](https://theajack.gitee.io/disable-devtool) | [更新日志](https://github.com/theajack/disable-devtool/blob/master/helper/version.md) | [Gitee](https://gitee.com/theajack/disable-devtool)**
## 1. 快速使用
### 1.1 npm 引用
```
npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
disableDevtool();
```
### 1.2 script属性配置
```html
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
```
或者通过版本引用:
```html
<!--使用指定版本-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x/disable-devtool.min.js'></script>
<!--使用最新版本-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest/disable-devtool.min.js'></script>
```
## 2.功能
disable-devtool 可以禁用所有一切可以进入开发者工具的方法,防止通过开发者工具进行的 ‘代码搬运’
该库有以下特性:
1. 支持可配置是否禁用右键菜单
2. 禁用 f12 和 ctrl+shift+i 快捷键
3. 支持识别从浏览器菜单栏打开开发者工具并关闭当前页面
4. 开发者可以绕过禁用 (url参数使用tk配合md5加密)
5. 支持几乎所有浏览器IE,360,qq浏览器,FireFox,Chrome,Edge...
6. 高度可配置
7. 使用极简、体积小巧 (仅7kb)
8. 支持npm引用和script标签引用(属性配置)
9. 识别真移动端与浏览器开发者工具设置插件伪造的移动端,为移动端节省性能
## 3. 使用
### 3.1 npm使用时的配置参数
安装 disable-devtool
```
npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
disableDevtool(options);
```
options中的参数与说明如下
```ts
declare interface optionStatic {
md5?: string; // 绕过禁用的md5值详情见3.2,默认不启用绕过禁用
url?: string; // 关闭页面失败时的跳转页面默认值为localhost
tkName?: string; // 绕过禁用时的url参数名称默认为 ddtk
ondevtoolopen?(): void; // 开发者面板打开的回调启用时url参数无效
interval?: number; // 定时器的时间间隔 默认200ms
disableMenu?: boolean; // 是否禁用右键菜单 默认为true
stopIntervalTime?: number; // 在移动端时取消监视的等待时长
}
```
### 3.2 md5 与 tk 绕过禁用
该库中使用 key 与 md5 配合的方式使得开发者可以在线上绕过禁用。
流程如下:
先指定一个 key a该值不要记录在代码中使用 md5 加密得到一个值 b将b作为 md5 参数传入,开发者在访问 url 的时候只需要带上url参数 ddtk=a便可以绕过禁用。
disableDevtool对象暴露了 md5 方法,可供开发者加密时使用:
```js
disableDevtool.md5('xxx');
```
### 3.3 script使用属性配置
```html
<script
disable-devtool-auto
src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'
md5='xxx'
url='xxx'
tk-name='xxx'
interval='xxx'
disable-menu='xxx'
></script>
```
注:
1. 如希望自动禁用,属性配置时必须要带上 `disable-devtool-auto` 属性
2. 属性配置都是可选的字段与3.1中一致,区别是将驼峰形式改成横线分割
3. 该script标签建议放在body最底部
### 3.4 script不使用属性配置
```html
<script src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
<script>
DisableDevtool({
// 参数与3.1中一致
})
</script>
```

View File

@ -1,142 +0,0 @@
<h1><a href='https://www.github.com/theajack/disable-devtool'>Disable-devtool</a></h1>
<h2>🚀 Disable web developer tools with one line </h2>
----
<p align="">
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/github/stars/theajack/disable-devtool.svg?style=social" alt="star"></a>
<a href="https://theajack.gitee.io"><img src="https://img.shields.io/badge/author-theajack-blue.svg?style=social" alt="Author"></a>
</p>
<p align="">
<a href="https://www.npmjs.com/package/disable-devtool"><img src="https://img.shields.io/npm/v/disable-devtool.svg" alt="Version"></a>
<a href="https://npmcharts.com/compare/disable-devtool?minimal=true"><img src="https://img.shields.io/npm/dm/disable-devtool.svg" alt="Downloads"></a>
<a href="https://cdn.jsdelivr.net/gh/theajack/disable-devtool/dist/disable-devtool.latest.min.js"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/disable-devtool.svg" alt="License"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a>
</p>
**[中文](https://github.com/theajack/disable-devtool/blob/master/README.cn.md) | [online trial/document](https://theajack.gitee.io/disable-devtool) | [Version Log](https://github.com/theajack/disable-devtool/blob/master/helper/version.md) | [Gitee](https://gitee.com/theajack/disable-devtool)**
## 1. Quick use
### 1.1 npm reference
```
npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
disableDevtool();
```
### 1.2 script attribute configuration
```html
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
```
Or use cdn with version:
```html
<!--Use a specific version-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x/disable-devtool.min.js'></script>
<!--Use latest version-->
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest/disable-devtool.min.js'></script>
```
## 2. Function
disable-devtool can disable all the methods that can enter the developer tools to prevent code handling through the developer tools
The library has the following features:
1. Support configurable whether to disable the right-click menu
2. Disable f12 and ctrl+shift+i shortcuts
3. Support recognition to open the developer tools from the browser menu bar and close the current page
4. Developers can bypass the disablement (use tk and md5 encryption for url parameters)
5. Support almost all browsers (IE,360,qq browser,FireFox,Chrome,Edge...)
6. Highly configurable
7. Minimal use, small size (only 7kb)
8. Support npm reference and script tag reference (attribute configuration)
9. Identify the real mobile terminal and browser developer tool settings plug-in forged mobile terminal, saving performance for the mobile terminal
## 3. Use
### 3.1 Configuration parameters when using npm
Install disable-devtool
```
npm i disable-devtool
```
```js
import disableDevtool from 'disable-devtool';
disableDevtool(options);
```
The parameters and descriptions in options are as follows:
```ts
declare interface optionStatic {
md5?: string; // Bypass the disabled md5 value, see 3.2 for details, the bypass disable is not enabled by default
url?: string; // Jump to the page when closing the page fails, the default value is localhost
tkName?: string; // Bypass the url parameter name when disabled, the default is ddtk
ondevtoolopen?(): void; // Callback for opening the developer panel, the url parameter is invalid when enabled
interval?: number; // Timer interval is 200ms by default
disableMenu?: boolean; // Whether to disable the right-click menu The default is true
stopIntervalTime?: number; // Waiting time to cancel monitoring on mobile
}
```
### 3.2 md5 and tk bypass disable
The combination of key and md5 in the library allows developers to bypass the disabling online.
The process is as follows:
First specify a key a (the value should not be recorded in the code), use md5 encryption to obtain a value b, and pass in b as the md5 parameter. Developers only need to bring the url parameter ddtk=a when accessing the url. Bypass disabled.
The disableDevtool object exposes the md5 method, which can be used by developers when encrypting:
```js
disableDevtool.md5('xxx');
```
### 3.3 script uses attribute configuration
```html
<script
disable-devtool-auto
src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'
md5='xxx'
url='xxx'
tk-name='xxx'
interval='xxx'
disable-menu='xxx'
></script>
```
Note:
1. If you want to automatically disable,you must bring the `disable-devtool-auto` attribute when configuring attributes
2. Attribute configuration is optional, the fields are the same as in 3.1, the difference is that the hump form is changed to horizontal line division
3. The script tag is recommended to be placed at the bottom of the body
### 3.4 script does not use attribute configuration
```html
<script src='https://cdn.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js'></script>
<script>
DisableDevtool({
// The parameters are the same as in 3.1
})
</script>
```

File diff suppressed because one or more lines are too long

18
npm/index.d.ts vendored
View File

@ -1,18 +0,0 @@
declare interface optionStatic {
md5?: string; // 绕过禁用的md5值详情见3.2,默认不启用绕过禁用
url?: string; // 关闭页面失败时的跳转页面默认值为localhost
tkName?: string; // 绕过禁用时的url参数名称默认为 ddtk
ondevtoolopen?(): void; // 开发者面板打开的回调启用时url参数无效
interval?: number; // 定时器的时间间隔 默认200ms
disableMenu?: boolean; // 是否禁用右键菜单 默认为true
stopIntervalTime?: number; // 在移动端时取消监视的等待时长
}
declare interface DDTStatic {
(option?: optionStatic): void;
md5(text?: string): string;
version: string;
}
declare const ddt: DDTStatic;
export default ddt;

View File

@ -1,24 +0,0 @@
{
"name": "disable-devtool",
"version": "0.1.1",
"description": "Disable web developer tools from the f12 button, right-click and browser ",
"main": "disable-devtool.min.js",
"unpkg": "disable-devtool.min.js",
"jsdelivr": "disable-devtool.min.js",
"typings": "index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/theajack/disable-devtool"
},
"keywords": [
"disable-devtool",
"禁用F12",
"禁用开发者工具"
],
"author": "theajack",
"license": "MIT",
"bugs": {
"url": "https://github.com/theajack/disable-devtool/issues"
},
"homepage": ""
}

11476
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,17 @@
{
"scripts": {
"lint": "eslint src --ext ts",
"_dev": "node scripts/dev.js",
"_serve": "serve scripts/dev",
"dev": "run-p _dev _serve",
"build": "node scripts/build/build.js",
"sync-version": "node helper/mod-index-html-version.js",
"build:docs": "node scripts/build/docs/build-docs.js",
"purge": "node scripts/purge-cdn.js",
"release": "node scripts/push-release.js"
},
"name": "disable-devtool",
"version": "0.1.1",
"version": "0.3.7",
"description": "Disable web developer tools from the f12 button, right-click and browser ",
"main": "disable-devtool.min.js",
"unpkg": "disable-devtool.min.js",
@ -10,14 +21,6 @@
"url": "https://github.com/theajack/disable-devtool/issues"
},
"homepage": "",
"scripts": {
"dev": "webpack-dev-server --open --config webpack-config/dev.js",
"start": "npm run dev",
"build": "webpack --config webpack-config/build.js",
"publish": "npm publish npm",
"lint": "eslint src --ext js",
"sync-version": "node helper/mod-index-html-version.js"
},
"author": "theajack",
"repository": {
"type": "git",
@ -30,34 +33,33 @@
],
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "^7.6.3",
"@commitlint/cli": "^8.2.0",
"@commitlint/config-conventional": "^8.2.0",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"eslint": "^6.5.1",
"eslint-config-standard": "^14.1.0",
"eslint-loader": "^3.0.2",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-rename": "^2.0.0",
"husky": "^3.0.9",
"lint-staged": "^9.4.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.2"
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
"@babel/preset-typescript": "^7.17.12",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-replace": "^4.0.0",
"@rollup/plugin-yaml": "^3.1.0",
"@types/node": "^18.0.1",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"esbuild": "^0.14.47",
"esbuild-plugin-d.ts": "^1.1.0",
"esbuild-plugin-yaml": "^0.0.1",
"eslint": "^8.18.0",
"execa": "4.0.2",
"lerna": "^5.1.5",
"npm-run-all": "^4.1.5",
"rollup": "^2.75.7",
"rollup-plugin-dts": "^4.2.2",
"rollup-plugin-typescript2": "^0.32.1",
"rollup-plugin-uglify": "^6.0.4",
"serve": "^13.0.2",
"typescript": "^4.7.4"
},
"dependencies": {},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
}
}

7468
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Disable Devtool Demo</title>
</head>
<body>
<script src="./bundle.js"></script>
<!-- <script id='disable-devtool'
md5='d4de605ccb923b7e876b3218a1474653'
tk-name='tk'
src="../npm/disable-devtool.min.js"></script> -->
</body>
</html>

View File

@ -1,18 +0,0 @@
import disableDevtool from '../src';
// import disableDevtool from '../npm';
// debugger;
disableDevtool({
md5: 'd4de605ccb923b7e876b3218a1474653',
// url: 'https://www.qq.com',
// ondevtoolopen: () => {
// window.location.href = 'https://www.qq.com';
// },
interval: 1000,
tkName: 'xx',
// url: 'https://www.baidu.com'
});
console.log(disableDevtool.version);
console.log(disableDevtool.md5('theajack'));

46
scripts/build/build.js Normal file
View File

@ -0,0 +1,46 @@
/*
* @Author: tackchen
* @Date: 2022-08-03 21:07:04
* @Description: Coding something
*/
const execa = require('execa');
const {resolveRootPath, copyFile, buildPackageJson, writeJsonIntoFile, write} = require('./utils');
const pkg = require('../../package.json');
async function build () {
await execa(
'node',
[
resolveRootPath('node_modules/rollup/dist/bin/rollup'),
'-c',
resolveRootPath('scripts/build/rollup.config.js'),
// '--environment',
// [
// `PACKAGE_NAME:${dirName}`,
// ],
],
{stdio: 'inherit'},
);
}
async function main () {
const version = process.argv[2];
if (!version) throw new Error('Invalid version');
pkg.version = version;
writeJsonIntoFile('@package.json', pkg);
write('@src/version.ts', `export default '${pkg.version}';`);
await build();
buildPackageJson();
copyFiles();
}
function copyFiles () {
copyFile('@LICENSE', '@npm/LICENSE');
copyFile('@README.md', '@npm/README.md');
}
main();

238
scripts/build/docs/404.html Normal file
View File

@ -0,0 +1,238 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Not allowed</title>
</head>
<body style="text-align: center;margin-top: 100px;">
<div">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800 600" style="visibility: visible; max-width: 400px;">
<g>
<defs>
<clipPath id="GlassClip">
<path d="M380.857,346.164c-1.247,4.651-4.668,8.421-9.196,10.06c-9.332,3.377-26.2,7.817-42.301,3.5
s-28.485-16.599-34.877-24.192c-3.101-3.684-4.177-8.66-2.93-13.311l7.453-27.798c0.756-2.82,3.181-4.868,6.088-5.13
c6.755-0.61,20.546-0.608,41.785,5.087s33.181,12.591,38.725,16.498c2.387,1.682,3.461,4.668,2.705,7.488L380.857,346.164z"></path>
</clipPath>
<clipPath id="cordClip">
<rect width="800" height="600"></rect>
</clipPath>
</defs>
<g id="planet" transform="matrix(0.9998,-0.0178,0.0178,0.9998,-1.8231,10.1314)" style="transform-origin: 0px 0px;">
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-miterlimit="10" cx="572.859" cy="108.803" r="90.788"></circle>
<circle id="craterBig" fill="none" stroke="#0E0620" stroke-width="3" stroke-miterlimit="10" cx="548.891" cy="62.319" r="13.074" transform="matrix(1,0,0,1,1.528,0)" style="transform-origin: 0px 0px;"></circle>
<circle id="craterSmall" fill="none" stroke="#0E0620" stroke-width="3" stroke-miterlimit="10" cx="591.743" cy="158.918" r="7.989" transform="matrix(1,0,0,1,-1.528,0)" style="transform-origin: 0px 0px;"></circle>
<path id="ring" fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" d="
M476.562,101.461c-30.404,2.164-49.691,4.221-49.691,8.007c0,6.853,63.166,12.408,141.085,12.408s141.085-5.555,141.085-12.408
c0-3.378-15.347-4.988-40.243-7.225"></path>
<path id="ringShadow" opacity="0.5" fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" d="
M483.985,127.43c23.462,1.531,52.515,2.436,83.972,2.436c36.069,0,68.978-1.19,93.922-3.149"></path>
</g>
<g id="stars">
<g id="starsBig">
<g transform="matrix(0.9938,-0.1111,0.1111,0.9938,-25.2271,59.1446)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="518.07" y1="245.375" x2="518.07" y2="266.581"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="508.129" y1="255.978" x2="528.01" y2="255.978"></line>
</g>
<g transform="matrix(0.9345,-0.3559,0.3559,0.9345,-76.0029,70.8548)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="154.55" y1="231.391" x2="154.55" y2="252.598"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="144.609" y1="241.995" x2="164.49" y2="241.995"></line>
</g>
<g transform="matrix(0.9992,-0.0405,0.0405,0.9992,-5.5495,13.0801)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="320.135" y1="132.746" x2="320.135" y2="153.952"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="310.194" y1="143.349" x2="330.075" y2="143.349"></line>
</g>
<g transform="matrix(0.9941,-0.1085,0.1085,0.9941,-52.3839,24.6857)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="200.67" y1="483.11" x2="200.67" y2="504.316"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="210.611" y1="493.713" x2="190.73" y2="493.713"></line>
</g>
</g>
<g id="starsSmall">
<g transform="matrix(1,0,0,1,0,0)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="432.173" y1="380.52" x2="432.173" y2="391.83"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="426.871" y1="386.175" x2="437.474" y2="386.175"></line>
</g>
<g transform="matrix(0.964,0,0,0.9647,17.624,10.7292)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="489.555" y1="299.765" x2="489.555" y2="308.124"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="485.636" y1="303.945" x2="493.473" y2="303.945"></line>
</g>
<g transform="matrix(0.849,0,0,0.8495,34.9517,44.4259)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="231.468" y1="291.009" x2="231.468" y2="299.369"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="227.55" y1="295.189" x2="235.387" y2="295.189"></line>
</g>
<g transform="matrix(0.654,0,0,0.6543,84.4349,190.7291)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="244.032" y1="547.539" x2="244.032" y2="555.898"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="247.95" y1="551.719" x2="240.113" y2="551.719"></line>
</g>
<g transform="matrix(0.379,0,0,0.3791,115.7286,255.2809)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="186.359" y1="406.967" x2="186.359" y2="415.326"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="190.277" y1="411.146" x2="182.44" y2="411.146"></line>
</g>
<g transform="matrix(0.023,0,0,0.0239,469.2497,401.3201)" style="transform-origin: 0px 0px;">
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="480.296" y1="406.967" x2="480.296" y2="415.326"></line>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="484.215" y1="411.146" x2="476.378" y2="411.146"></line>
</g>
</g>
<g id="circlesBig">
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="588.977" cy="255.978" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="450.066" cy="320.259" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="168.303" cy="353.753" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="429.522" cy="201.185" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="200.67" cy="176.313" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="133.343" cy="477.014" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="283.521" cy="568.033" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
<circle fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" cx="413.618" cy="482.387" r="7.952" transform="matrix(1,0,0,1,0,-1.018)" style="transform-origin: 0px 0px;"></circle>
</g>
<g id="circlesSmall">
<circle fill="#0E0620" cx="549.879" cy="296.402" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
<circle fill="#0E0620" cx="253.29" cy="229.24" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
<circle fill="#0E0620" cx="434.824" cy="263.931" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
<circle fill="#0E0620" cx="183.708" cy="544.176" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
<circle fill="#0E0620" cx="382.515" cy="530.923" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
<circle fill="#0E0620" cx="130.693" cy="305.608" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
<circle fill="#0E0620" cx="480.296" cy="477.014" r="2.651" transform="matrix(1,0,0,1,0,-2.037)" style="transform-origin: 0px 0px;"></circle>
</g>
</g>
<g id="spaceman" clip-path="url(cordClip)" transform="matrix(1,0.0089,-0.0089,1,1.9668,0.7195)" style="transform-origin: 0px 0px;">
<path id="cord" fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M273.813,410.969c0,0-54.527,39.501-115.34,38.218c-2.28-0.048-4.926-0.241-7.841-0.548
c-68.038-7.178-134.288-43.963-167.33-103.87c-0.908-1.646-1.793-3.3-2.654-4.964c-18.395-35.511-37.259-83.385-32.075-118.817"></path>
<path id="backpack" fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M338.164,454.689l-64.726-17.353c-11.086-2.972-17.664-14.369-14.692-25.455l15.694-58.537
c3.889-14.504,18.799-23.11,33.303-19.221l52.349,14.035c14.504,3.889,23.11,18.799,19.221,33.303l-15.694,58.537
C360.647,451.083,349.251,457.661,338.164,454.689z"></path>
<g id="antenna">
<line fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="323.396" y1="236.625" x2="295.285" y2="353.753"></line>
<circle fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" cx="323.666" cy="235.617" r="6.375"></circle>
</g>
<g id="armR">
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M360.633,363.039c1.352,1.061,4.91,5.056,5.824,6.634l27.874,47.634c3.855,6.649,1.59,15.164-5.059,19.02l0,0
c-6.649,3.855-15.164,1.59-19.02-5.059l-5.603-9.663"></path>
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M388.762,434.677c5.234-3.039,7.731-8.966,6.678-14.594c2.344,1.343,4.383,3.289,5.837,5.793
c4.411,7.596,1.829,17.33-5.767,21.741c-7.596,4.411-17.33,1.829-21.741-5.767c-1.754-3.021-2.817-5.818-2.484-9.046
C375.625,437.355,383.087,437.973,388.762,434.677z"></path>
</g>
<g id="armL">
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M301.301,347.66c-1.702,0.242-5.91,1.627-7.492,2.536l-47.965,27.301c-6.664,3.829-8.963,12.335-5.134,18.999h0
c3.829,6.664,12.335,8.963,18.999,5.134l9.685-5.564"></path>
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M241.978,395.324c-3.012-5.25-2.209-11.631,1.518-15.977c-2.701-0.009-5.44,0.656-7.952,2.096
c-7.619,4.371-10.253,14.09-5.883,21.71c4.371,7.619,14.09,10.253,21.709,5.883c3.03-1.738,5.35-3.628,6.676-6.59
C252.013,404.214,245.243,401.017,241.978,395.324z"></path>
</g>
<g id="body">
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M353.351,365.387c-7.948,1.263-16.249,0.929-24.48-1.278c-8.232-2.207-15.586-6.07-21.836-11.14
c-17.004,4.207-31.269,17.289-36.128,35.411l-1.374,5.123c-7.112,26.525,8.617,53.791,35.13,60.899l0,0
c26.513,7.108,53.771-8.632,60.883-35.158l1.374-5.123C371.778,395.999,365.971,377.536,353.351,365.387z"></path>
<path fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M269.678,394.912L269.678,394.912c26.3,20.643,59.654,29.585,93.106,25.724l2.419-0.114"></path>
</g>
<g id="legs">
<g id="legR">
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M312.957,456.734l-14.315,53.395c-1.896,7.07,2.299,14.338,9.37,16.234l0,0c7.07,1.896,14.338-2.299,16.234-9.37l17.838-66.534
C333.451,455.886,323.526,457.387,312.957,456.734z"></path>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="304.883" y1="486.849" x2="330.487" y2="493.713"></line>
</g>
<g id="legL">
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M296.315,452.273L282,505.667c-1.896,7.07-9.164,11.265-16.234,9.37l0,0c-7.07-1.896-11.265-9.164-9.37-16.234l17.838-66.534
C278.993,441.286,286.836,447.55,296.315,452.273z"></path>
<line fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="262.638" y1="475.522" x2="288.241" y2="482.387"></line>
</g>
</g>
<g id="head">
<ellipse transform="matrix(0.259 -0.9659 0.9659 0.259 -51.5445 563.2371)" fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" cx="341.295" cy="315.211" rx="61.961" ry="60.305"></ellipse>
<path id="headStripe" fill="none" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M330.868,261.338c-7.929,1.72-15.381,5.246-21.799,10.246" transform="matrix(1,0.0089,-0.0089,1,2.3259,-2.4967)" style="transform-origin: 0px 0px;"></path>
<path fill="#FFFFFF" stroke="#0E0620" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M380.857,346.164c-1.247,4.651-4.668,8.421-9.196,10.06c-9.332,3.377-26.2,7.817-42.301,3.5s-28.485-16.599-34.877-24.192
c-3.101-3.684-4.177-8.66-2.93-13.311l7.453-27.798c0.756-2.82,3.181-4.868,6.088-5.13c6.755-0.61,20.546-0.608,41.785,5.087
s33.181,12.591,38.725,16.498c2.387,1.682,3.461,4.668,2.705,7.488L380.857,346.164z"></path>
<g clip-path="url(#GlassClip)">
<polygon id="glassShine" fill="none" stroke="#0E0620" stroke-width="3" stroke-miterlimit="10" points="
278.436,375.599 383.003,264.076 364.393,251.618 264.807,364.928 " transform="matrix(0.866,-0.5,0.5,0.866,-33.401,203.976)" style="transform-origin: 0px 0px;"></polygon>
</g>
</g>
</g>
</g>
</svg>
</div>
<div style='
font-size: 40px;
font-family: microsoft Yahei;
margin-top: 20px;
'>What Are You Looking For</div>
<div style='
font-size: 40px;
font-family: microsoft Yahei;
margin-top: 10px;
'>From &lt;<span id='host'>Me</span>&gt;?</div>
<script>
var host = getUrlParam('h');
if(host){
document.getElementById('host').innerText = host
}
function getUrlParam (name) {
var search = window.location.search;
if (search !== '') {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
}
return '';
}
</script>
</body>
</html>

View File

@ -0,0 +1,20 @@
/*
* @Author: tackchen
* @Date: 2022-09-28 00:48:05
* @Description: Coding something
*/
const {read, write, mkdirDir, copyFile} = require('../utils');
function modIndexHtmlVersion () {
const version = process.argv[2] || 'latest';
const html = read('@scripts/build/docs/index.html');
const res = html.match(new RegExp(`https://cdn.jsdelivr.net/npm/disable-devtool@.*/disable-devtool.min.js#use`));
mkdirDir('@docs');
if (res) {
copyFile('@.gitignore', '@docs/.gitignore');
copyFile('@scripts/build/docs/404.html', '@docs/404.html');
write('@docs/index.html', html.replace(res[0], `https://cdn.jsdelivr.net/npm/disable-devtool@${version}/disable-devtool.min.js#use`));
}
}
modIndexHtmlVersion();

View File

@ -0,0 +1,150 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Disable web developer tools with one line</title>
<style>
code{
white-space: pre;
font-family: Consolas, "Courier New", monospace;
color: #fff;
background-color: #444;
display: block;
overflow-x: auto;
border-radius: 5px;
padding: 10px;
}
body{
max-width: 1000px;
margin: 0 auto;
padding: 0 20px;
}
</style>
</head>
<body>
<h1><a style='color:#222' href='https://www.github.com/theajack/disable-devtool'>Disable-devtool</a></h1>
<h3 id="version"></h3>
<h3>
Now that the devtool on this page has been disabled, use the <a href='https://theajack.github.io/disable-devtool?ddtk=dd'>?ddtk=dd</a> url parameter to un-disable (ddtk value is configurable)
</h3>
<h2>🚀 Disable web developer tools with one line </h2>
<p>
<a href="https://www.github.com/theajack/disable-devtool/stargazers" target="_black">
<img src="https://img.shields.io/github/stars/theajack/disable-devtool?logo=github" alt="stars" />
</a>
<a href="https://www.github.com/theajack/disable-devtool/network/members" target="_black">
<img src="https://img.shields.io/github/forks/theajack/disable-devtool?logo=github" alt="forks" />
</a>
<a href="https://www.npmjs.com/package/disable-devtool" target="_black">
<img src="https://img.shields.io/npm/v/disable-devtool?logo=npm" alt="version" />
</a>
<a href="https://www.npmjs.com/package/disable-devtool" target="_black">
<img src="https://img.shields.io/npm/dm/disable-devtool?color=%23ffca28&logo=npm" alt="downloads" />
</a>
<a href="https://www.jsdelivr.com/package/npm/disable-devtool" target="_black">
<img src="https://data.jsdelivr.com/v1/package/npm/disable-devtool/badge" alt="jsdelivr" />
</a>
<a href="https://github.com/theajack/disable-devtool/issues"><img src="https://img.shields.io/github/issues-closed/theajack/disable-devtool.svg" alt="issue"></a>
</p>
<p>
<a href="https://github.com/theajack" target="_black">
<img src="https://img.shields.io/badge/Author-%20theajack%20-7289da.svg?&logo=github" alt="author" />
</a>
<a href="https://www.github.com/theajack/disable-devtool/blob/master/LICENSE" target="_black">
<img src="https://img.shields.io/github/license/theajack/disable-devtool?color=%232DCE89&logo=github" alt="license" />
</a>
<a href="https://cdn.jsdelivr.net/npm/disable-devtool"><img src="https://img.shields.io/bundlephobia/minzip/disable-devtool.svg" alt="Size"></a>
<a href="https://github.com/theajack/disable-devtool/search?l=javascript"><img src="https://img.shields.io/github/languages/top/theajack/disable-devtool.svg" alt="TopLang"></a>
<a href="https://www.github.com/theajack/disable-devtool"><img src="https://img.shields.io/librariesio/dependent-repos/npm/disable-devtool.svg" alt="Dependent"></a>
<a href="https://github.com/theajack/disable-devtool/blob/master/test/test-report.txt"><img src="https://img.shields.io/badge/test-passed-44BB44" alt="test"></a>
</p>
<p>
<strong>
<a href='https://www.github.com/theajack/disable-devtool'>Github</a></h1>
| <a href="https://github.com/theajack/disable-devtool/blob/master/README.cn.md">中文文档</a>
| <a href="https://github.com/theajack/disable-devtool/blob/master/README.md">English Docs</a>
| <a href="https://github.com/theajack/disable-devtool/blob/master/helper/version.en.md">Version Log</a>
| <a href="https://theajack.github.io/message-board?app=disable-devtool">Message Board</a>
</strong>
</p>
<h3>
Open source maintenance is not easy, if you have the financial means, you can donate the author for a cup of coffee
</h3>
<p>
<a href="https://ko-fi.com/theajack">
<img src="https://img.shields.io/badge/Donate-Ko Fi-ff5f5f" alt="test">
</a>
<a href="https://paypal.me/tackchen">
<img src="https://img.shields.io/badge/Donate-PayPal-142c8e" alt="test">
</a>
<a href="https://shiyix.cn/images/wx-pay.png">
<img src="https://img.shields.io/badge/Donate-Wechat Pay-00c250" alt="test">
</a>
</p>
<h2>1. Quick use</h2>
<h3>1.1 npm reference</h3>
<p><code>npm i disable-devtool</code></p>
<p>
<code>import disableDevtool from&#39;disable-devtool&#39;;
disableDevtool();</code>
</p>
<h3>1.2 script attribute configuration</h3>
<p><code>&lt;script disable-devtool-auto src=&#39;https://cdn.jsdelivr.net/npm/disable-devtool&#39;&gt;&lt;/script&gt;</code></p>
<p>Or use cdn with version:</p>
<p><code>&lt;!--Use a specific version-->
&lt;script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@x.x.x'>&lt;/script>
&lt;!--Use latest version-->
&lt;script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool@latest'>&lt;/script></code></p>
<div style="margin-bottom: 50px">
TOOL:
<input type="text" id='md5_key' placeholder="Enter a key">
<button onclick="generateMd5()">Generate md5 tk</button>
<span id='md5_value'></span>
</div>
<script
disable-devtool-auto
md5='1aabac6d068eef6a7bad3fdf50a05cc8'
src='https://cdn.jsdelivr.net/npm/disable-devtool@0.2.6/disable-devtool.min.js#use'
></script>
<script>
document.getElementById('version').innerText = 'version = ' + DisableDevtool.version;
function setText(text){
document.getElementById('md5_value').innerText = text;
}
function generateMd5(){
if(!window.DisableDevtool){
alert('DisableDevtool not ready');
return;
}
let key = document.getElementById('md5_key').value;
if(!key){
alert('Key is empty');
return;
}
setText(DisableDevtool.md5(key));
}
</script>
</body>
</html>

View File

@ -0,0 +1,61 @@
/*
* @Author: tackchen
* @Date: 2022-08-03 20:40:33
* @Description: Coding something
*/
import {nodeResolve} from '@rollup/plugin-node-resolve';
import {babel} from '@rollup/plugin-babel';
import dts from 'rollup-plugin-dts';
import typescript from 'rollup-plugin-typescript2';
import yaml from '@rollup/plugin-yaml';
import commonjs from '@rollup/plugin-commonjs';
import {uglify} from 'rollup-plugin-uglify';
import packageInfo from '../../package.json';
const {
resolveRootPath,
} = require('./utils');
const extensions = ['.ts', '.d.ts', '.js'];
const inputFile = resolveRootPath('src/index.ts');
const config = [
{
// 编译typescript, 生成 js 文件
input: inputFile,
output: {
file: resolveRootPath('npm/disable-devtool.min.js'),
format: 'umd',
name: 'DisableDevtool',
},
plugins: [
uglify(),
commonjs(),
yaml(),
typescript(),
nodeResolve({
extensions,
}),
babel({
exclude: 'node_modules/**',
extensions,
}),
],
// sourceMap: true,
external: packageInfo.dependencies,
},
{
// 生成 .d.ts 类型声明文件
input: inputFile,
output: {
file: resolveRootPath('npm/index.d.ts'),
format: 'es',
},
plugins: [dts()],
},
];
export default config;

118
scripts/build/utils.js Normal file
View File

@ -0,0 +1,118 @@
/*
* @Author: tackchen
* @Date: 2022-08-03 20:41:31
* @Description: Coding something
*/
const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
function resolveRootPath (str) {
return path.resolve(__dirname, `../../${str}`);
}
function upcaseFirstLetter (str) {
if (typeof str !== 'string' || !str) return '';
return str[0].toUpperCase() + str.substr(1);
}
function writeJsonIntoFile (filePath, pkg) {
fs.writeFileSync(transfromFilePath(filePath), JSON.stringify(pkg, null, 4), 'utf8');
}
function writeStringIntoFile (filePath, str) {
fs.writeFileSync(transfromFilePath(filePath), str, 'utf8');
}
function copyFile (src, dest) {
fs.copyFileSync(transfromFilePath(src), transfromFilePath(dest));
}
function transfromFilePath (filePath) {
if (filePath[0] === '@') {
return resolveRootPath(filePath.substr(1));
}
return filePath;
}
function mkdirDir (filePath) {
filePath = transfromFilePath(filePath);
if (!fs.existsSync(filePath)) {
console.log('mkdirSync', filePath);
fs.mkdirSync(filePath);
}
}
function clearDirectory (dirPath) {
dirPath = transfromFilePath(dirPath);
if (!fs.existsSync(dirPath)) return;
clearDirectoryBase(dirPath);
}
function clearDirectoryBase (dirPath) {
const files = fs.readdirSync(dirPath);
files.forEach((file) => {
const filePath = `${dirPath}/${file}`;
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
clearDirectoryBase(filePath);
fs.rmdirSync(filePath);
} else {
fs.unlinkSync(filePath);
}
});
};
function buildPackageJson (extract = {}) {
const pkg = require(resolveRootPath('package.json'));
const attrs = ['name', 'version', 'description', 'main', 'unpkg', 'jsdelivr', 'typings', 'repository', 'keywords', 'author', 'license', 'bugs', 'homepage', 'dependencies'];
const npmPkg = {};
attrs.forEach(key => {
npmPkg[key] = pkg[key] || '';
});
for (const key in extract) {
npmPkg[key] = extract[key];
}
mkdirDir('@npm');
writeJsonIntoFile('@npm/package.json', npmPkg);
}
async function exec (cmd) {
return new Promise(resolve => {
childProcess.exec(cmd, function (error, stdout, stderr) {
if (error) {
resolve({success: false, stdout, stderr});
} else {
resolve({
success: true,
stdout,
stderr
});
}
});
});
}
module.exports = {
copyFile,
resolveRootPath,
transfromFilePath,
upcaseFirstLetter,
writeJsonIntoFile,
writeStringIntoFile,
buildPackageJson,
clearDirectory,
mkdirDir,
read: function (file) {
return fs.readFileSync(transfromFilePath(file), 'utf8'); ;
},
write: function (file, txt) {
fs.writeFileSync(transfromFilePath(file), txt, 'utf8');
},
exec,
};

41
scripts/dev.js Normal file
View File

@ -0,0 +1,41 @@
/*
* @Author: tackchen
* @Date: 2022-08-03 20:37:59
* @Description: Coding something
*/
const {build} = require('esbuild');
const {resolve} = require('path');
const {yamlPlugin} = require('esbuild-plugin-yaml');
const {dtsPlugin} = require('esbuild-plugin-d.ts');
const outfile = resolve(__dirname, './dev/bundle.js');
build({
entryPoints: [resolve(__dirname, './dev/index.ts')],
outfile,
bundle: true,
sourcemap: true,
format: 'cjs',
globalName: 'LernaDemo',
platform: 'browser',
// plugins:
// format === 'cjs' || pkg.buildOptions?.enableNonBrowserBranches
// ? [nodePolyfills.default()]
// : undefined,
// define: {
// __COMMIT__: '"dev"',
// __VERSION__: `"${pkg.version}"`,
// },
plugins: [
yamlPlugin(),
dtsPlugin(),
],
watch: {
onRebuild (error) {
if (!error) console.log(`rebuilt: ${outfile}`);
},
},
}).then(() => {
console.log(`watching: ${outfile}`);
});

17
scripts/dev/iframe.html Normal file
View File

@ -0,0 +1,17 @@
<!--
* @Author: chenzhongsheng
* @Date: 2023-02-16 23:40:42
* @Description: Coding something
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<iframe src="http://localhost:3000" frameborder="0"></iframe>
</body>
</html>

22
scripts/dev/index.html Normal file
View File

@ -0,0 +1,22 @@
<!--
* @Author: tackchen
* @Date: 2022-09-27 21:46:40
* @Description: Coding something
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>
<script src="./bundle.js"></script>
<!-- <p>Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy Test copy </p> -->
<div>Test disable select</div>
<input/>
</body>
</html>

72
scripts/dev/index.ts Normal file
View File

@ -0,0 +1,72 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 21:46:40
* @Description: Coding something
*/
import disableDevtool from '../../src';
// import disableDevtool from '../../npm';
// window.addEventListener('popstate', function (event) {
// event.preventDefault();
// });
disableDevtool({
md5: '0b9e05caf5000360ec1c263335bd83fe', // ddtk
// url: 'https://www.qq.com',
ondevtoolopen: (type, next) => {
// window.location.href = 'https://www.qq.com';
document.body.innerHTML = 'devtool opened!; type =' + type;
// next();
// console.log(next);
},
ondevtoolclose: () => {
// window.location.href = 'https://www.qq.com';
document.body.innerHTML = 'devtool closed!;';
// next();
// console.log(next);
},
clearIntervalWhenDevOpenTrigger: true,
interval: 1000,
// tkName: 'ddtk',
// disableMenu: false,
// clearLog: false,
// disableCopy: true,
// disableSelect: true,
// disablePaste: true,
// url: 'https://www.baidu.com'
// detectors: [disableDevtool.DetectorType.DATE_TO_STRING],
// ignore: ['aaaa', /[xy]+/],
// ignore: () => window.ignore === undefined
});
document.addEventListener('click', () => {
const div = document.createElement('div');
div.innerText = `isOpen = ${disableDevtool.isDevToolOpened()}`;
document.body.appendChild(div);
// alert(disableDevtool.isDevToolOpened());
// disableDevtool.isSuspend = !disableDevtool.isSuspend;
// alert(disableDevtool.isSuspend);
});
console.log(disableDevtool.version);
console.log(disableDevtool.md5('xx'));
// import {log} from '../src/log';
// setTimeout(() => {
// log(111);
// debugger;
// }, 3000);
// window.log = log;
// window.addEventListener('keydown', (e) => {
// const keyCode = e.keyCode || e.which;
// if ( keyCode === 123 ) {
// alert('xxxxxx');
// }
// });

View File

@ -0,0 +1,3 @@
src
node_modules
pnpm-lock.yaml

22
scripts/helper/tool.js Normal file
View File

@ -0,0 +1,22 @@
const childProcess = require('child_process');
async function exec (cmd) {
return new Promise((resolve) => {
childProcess.exec(cmd, (error, stdout, stderr) => {
if (error) {
console.log(error);
resolve({success: false, stdout, stderr});
} else {
resolve({
success: true,
stdout,
stderr,
});
}
});
});
}
module.exports = {
exec,
};

17
scripts/local/iframe.html Normal file
View File

@ -0,0 +1,17 @@
<!--
* @Author: chenzhongsheng
* @Date: 2023-02-16 23:40:42
* @Description: Coding something
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<iframe src="http://localhost:3000" frameborder="0"></iframe>
</body>
</html>

10
scripts/purge-cdn.js Normal file
View File

@ -0,0 +1,10 @@
/*
* @Author: tackchen
* @Date: 2022-09-28 19:52:23
* @Description: Coding something
*/
const https = require('https');
https.get(`https://purge.jsdelivr.net/npm/disable-devtool/disable-devtool.min.js`, () => {
});

39
scripts/push-release.js Normal file
View File

@ -0,0 +1,39 @@
/*
* @Author: tackchen
* @Date: 2022-04-06 09:14:55
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-09-28 22:02:53
* @FilePath: /cnchar/helper/push-release.js
* @Description: Coding something
*/
const {exec} = require('./build/utils');
async function delTag (tagName) {
await exec(`git tag -d ${tagName}`);
await exec(`git push origin :refs/tags/${tagName}`);
}
// 版本发布 del 表示需要覆盖上一个版本 一般不需要
// node ./helper/push-tag.js vx.x.x
// node ./helper/push-tag.js vx.x.x no-del
// npm run release -- vx.x.x
// npm run release -- vx.x.x no-del
async function main () {
const argv = process.argv.slice(2);
const tagName = argv[0];
if (argv[1] !== 'no-del') {
console.log(`Start delete tag ${tagName}...`);
await delTag(tagName);
}
console.log(`Start create tag ${tagName}...`);
await exec(`git tag -m "version ${tagName}" ${tagName} master`);
console.log(`Start push tag ${tagName}...`);
await exec('git push --tags');
console.log('Finished!');
}
main();

70
scripts/test/debug.html Normal file
View File

@ -0,0 +1,70 @@
<!--
* @Author: chenzhongsheng
* @Date: 2022-09-28 22:12:53
* @Description: Coding something
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='text'></div>
<script>
;(function () {
var src = 'http://cdn.jsdelivr.net/eruda/1.0.5/eruda.min.js';
document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
document.write('<scr' + 'ipt>eruda.init();</scr' + 'ipt>');
})();
</script>
<script src='../../npm/disable-devtool.min.js'></script>
<script>
const text = document.getElementById('text');
var detectors = getUrlParam('dt')
if(!detectors || detectors === 'all'){
detectors = 'all'
}else{
detectors = detectors.split(',')
}
console.log(detectors);
DisableDevtool({
md5: '0b9e05caf5000360ec1c263335bd83fe', // ddtk
// url: 'https://www.qq.com',
ondevtoolopen: function(type) {
// window.location.href = 'https://www.qq.com';
text.innerHTML += 'devtool opened!; type =' + type + '<br>';
// document.body.innerHTML = 'devtool opened!; type =' + type;
console.log(window.outerHeight, window.innerHeight)
// next();
// console.log(next);
},
ondevtoolclose: function(){
text.innerHTML = 'devtool closed!'
},
clearIntervalWhenDevOpenTrigger: false,
interval: 1000,
// tkName: 'ddtk',
// disableMenu: false,
// url: 'https://www.baidu.com'
detectors: detectors,
});
function getUrlParam (name) {
const search = window.location.search;
if (search !== '') {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
const r = search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
}
return '';
}
</script>
</body>
</html>

10
scripts/test/index.js Normal file
View File

@ -0,0 +1,10 @@
/*
* @Author: tackchen
* @Date: 2022-09-28 01:11:39
* @Description: Coding something
*/
import dd from '../../npm';
dd({
});

32
scripts/test/testcdn.html Normal file
View File

@ -0,0 +1,32 @@
<!--
* @Author: tackchen
* @Date: 2022-09-28 00:28:29
* @Description: Coding something
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Disable Devtool Demo</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>
// VConsole will be exported to `window.VConsole` by default.
var vConsole = new window.VConsole();
</script> -->
<!-- disable-devtool-auto -->
<script
disable-devtool-auto
md5='d4de605ccb923b7e876b3218a1474653'
tk-name='tk'
src="../../npm/disable-devtool.min.js"></script>
<script>
// DisableDevtool()
</script>
</body>
</html>

11
scripts/todo.md Normal file
View File

@ -0,0 +1,11 @@
<!--
* @Author: tackchen
* @Date: 2022-01-06 00:09:44
* @LastEditors: tackchen
* @LastEditTime: 2022-04-14 14:20:16
* @FilePath: /disable-devtool/helper/todo.md
* @Description: Coding something
-->
1. 问题ios真机chrome 浏览器 data-to-string 和 func-to-string两个detector与开发者工具表现一致
2. Windows qq浏览器最新版本 mac safari可能会误伤 问题

153
scripts/version.en.md Normal file
View File

@ -0,0 +1,153 @@
<!--
* @Author: tackchen
* @Date: 2022-08-28 20:56:33
* @Description: Coding something
-->
# Version Log:
## 0.3.7
1. Fix the movement of the mobile browser long press and not pop up the copy and other buttons
2. Add REWRITEHTML configuration
3. Remove CleardDinterval calls in Closewindow
## 0.3.6
1. Fix The new version of Google Lighthouse is not released
2. Fix The mobile debugging tool is allowed after 5s
3. Set the interval default time to 500ms
## 0.3.5
1. Fix the problem that the debugging mode in the PC iOS mobile terminal does not work
2. Remove the default enablement of sizeDetector
3. Add timeOutUrl to handle the jump that closes the page timeout
4. Add disableDevtool to repeatedly enable judgment and increase the return value
5. Optimize the judgment of seobot
## 0.3.4
Fix false detection issue in iOS Edge browser
## 0.3.3
1. Fixed the issue that an error may be reported in a non-browser environment
2. Add SEO protection function, and add config.seo parameter to control whether it needs to be enabled, the default is true
## 0.3.2
1. Add the isRunning property to return whether the detector is running
2. Add the isSuspend property to set Detector Hang or Detect whether it is suspended
3. Add the ignore configuration parameter, users matching certain URLs do not enable detectors
4. Fixed the bug that the parent window can open the console in the iframe, and added the disableIframeParents parameter to control the behavior
5. Fixed the issue that the default redirect link is invalid
## 0.3.1
1. Fixed false recognition in ios Chrome
## 0.3.0
1. ts reconstruction, using esbuild and rollback
2. Add the disablePaste parameter to disable the paste function
3. Add third-party debugging tools eruda and vconsole
## 0.2.6
1. Add the performance mode and fix the bug that the new version of chrome is incompatible
## 0.2.5
1. Add disableSelect, disableCopy, disableCut configuration
## 0.2.4
1. Fix the case of accidental injury under iosEdge
## 0.2.3
1. Opening the sidebar under edge will cause accidental injury, so disable sizeDetector under edge
2. Increase the clearLog parameter to control whether the console is required for each situation, the default is true
## 0.2.1 - 0.2.2
1. Add ondevtoolclose configuration
2. Add isDevToolOpened api
3. Fix the accidental injury problem of ios mobile chrome
4. Added a debug page
## 0.1.12
1. Add the second parameter next of config.ondevtoolopen
2. Add shortcut key operations for prohibiting review elements and saving webpages
3. Refactor the code
4. Fix the problem that ie cannot cache the methods on the console
## 0.1.11
1. Fix the accidental injury caused by the third-party hack console.log method
## 0.1.10
1. Fix the problem that sizeDetector accidentally hurts in browser zoom mode
## 0.1.9
1. Fix the bug of accidental injury in IFrame
## 0.1.8
1. Disable macos option+commond+i
2. Delete some debug code and useless code
3. Modify the event model
## 0.1.6 - 0.1.7
1. Add DateToString monitoring type
2. Add FuncToString monitoring type
3. Add detectors configuration
4. Fix ios 15 accidental injury problem
## 0.1.5
1. Remove the log-time monitoring type (because of inaccuracy)
## 0.1.4
1. Add detector, add multiple monitoring modes
2. Use logTime mode to get the bottom line, compatible with mac, linux
3. Add clearIntervalWhenDevOpenTrigger parameter
4. ondevtoolopen adds monitoring mode callback parameter
## 0.1.3
1. Fix the bug that disableMenu parameter is invalid
## 0.1.2
1. Add the judgment of the document to adapt to the server-side rendering npm call
## 0.1.1
1. Increase the delay of jumping to the default page after history.back
2. Optimize ondeltoolopen logic
## 0.1.0
1. Fix the invalid problem under firefox and qq browsers
2. Enable disableMenu configuration
3. Remove internal debug logic
4. Add the default 404 page to jump to
## 0.0.6
1. For tag attribute configuration, remove the id='disable-devtool' condition and use the disable-devtool-auto attribute
2. Modify the readme
## 0.0.5
1. Optimize onDevToolOpen event trigger logic
## 0.0.4
1. Modify the webpack packaging configuration
## 0.0.3
1. Solve the problem that native methods such as alert will affect the debug timing.
2. Solve the page and the background will affect the debug timing.
3. Compatible with ie, the disableMenu parameter is invalid under ie, because the right button under ie will block the main process and cannot monitor
4. Increase config.stopIntervalTime to indicate the waiting time for canceling monitoring on the mobile terminal
5. Optimize the logic for judging the opening of developer tools
## 0.0.2
1. Solve the bug of invalid cdn file
## 0.0.1
1. Support configurable whether to disable the right-click menu
2. Disable f12 and ctrl+shift+i shortcuts
3. Support recognition to open developer tools from browser menu bar and close the current page
4. Developers can bypass the disable (url parameters are encrypted with tk and md5)
5. Support almost all browsers
6. Highly configurable
7. Minimal use and small size (only 7kb)
8. Support npm reference and script tag reference (property configuration)

153
scripts/version.md Normal file
View File

@ -0,0 +1,153 @@
<!--
* @Author: tackchen
* @Date: 2022-08-28 20:56:33
* @Description: Coding something
-->
# Version Log:
## 0.3.7
1. 修复移动端浏览器长按不弹出复制等按钮
2. 增加 rewriteHTML 配置
3. 移除 closeWindow 中的 clearDDInterval 调用
## 0.3.6
1. fix google lighthouse 新版本没有放行
2. fix 移动端调试工具5s之后被放行
3. 将interval默认时间设置为500ms
## 0.3.5
1. 修复pc端ios移动端中调试模式不起作用的问题
2. 去除sizeDetector的默认启用
3. 增加timeOutUrl用来处理关闭页面超时的跳转
4. 增加disableDevtool重复启用判断增加返回值
5. 优化seobot的判断
## 0.3.4
1. 修复ios edge浏览器中的误检测问题
## 0.3.3
1. 修复在非浏览器环境引入可能报错的问题
2. 增加seo保护功能并增加 config.seo 参数用来控制是否需要开启默认为true
## 0.3.2
1. 增加 isRunning 属性,返回检测器是否正在运行
2. 增加 isSuspend 属性,设置检测器挂起 或 检测是否被挂起
3. 增加 ignore 配置参数用户匹配某些url不启用检测器
4. 修复iframe中父窗口可以打开控制台的bug并新增disableIframeParents参数控制该行为
5. 修复默认跳转链接失效的问题
## 0.3.1
1. 修复ios chrome中的误识别
## 0.3.0
1. ts重构使用esbuild与rollup
2. 增加 disablePaste 参数,禁用粘贴功能
3. 增加 检测第三方调试工具 eruda和vconsole
## 0.2.6
1. 增加performance模式修复新版本chrome不兼容的bug
## 0.2.5
1. 增加disableSelect, disableCopy, disableCut配置
## 0.2.4
1. 修复iosEdge下会误伤的情况
## 0.2.3
1. edge 下打开侧边栏会误伤所以禁用edge下的sizeDetector
2. 增加clearLog参数控制是否需要每次情况控制台默认为true
## 0.2.1 - 0.2.2
1. 增加 ondevtoolclose 配置
2. 增加 isDevToolOpened api
3. 修复 ios mobile chrome 的误伤问题
4. 增加了一个debug页面
## 0.1.12
1. 增加 config.ondevtoolopen 第二个参数 next
2. 增加 禁止审查元素和保存网页的快捷键操作
3. 重构代码
4. 修复ie不能缓存console上的方法导致的问题
## 0.1.11
1. 修复第三方 hack console.log方法 导致的误伤
## 0.1.10
1. 修复sizeDetector在浏览器缩放模式下误伤的问题
## 0.1.9
1. 修复IFrame中误伤的bug
## 0.1.8
1. 禁用 macos option+commond+i
2. 删除部分调试代码与无用代码
3. 修改事件模型
## 0.1.6 - 0.1.7
1. 增加 DateToString 监测类型
2. 增加 FuncToString 监测类型
3. 增加 detectors 配置
4. 修复ios 15误伤问题
## 0.1.5
1. 去掉log-time监测类型因为不准确
## 0.1.4
1. 增加 detector增加多种监测模式
2. 使用logTime模式兜底兼容maclinux
3. 增加 clearIntervalWhenDevOpenTrigger 参数
4. ondevtoolopen 增加 监测模式 回调参数
## 0.1.3
1. 修复 disableMenu 参数无效的bug
## 0.1.2
1. 加上document的判断 以适应服务端渲染 npm 调用
## 0.1.1
1. 增加history.back 之后跳转默认页的延迟
2. 优化ondeltoolopen 逻辑
## 0.1.0
1. 修复firefox和qq浏览器下无效的问题
2. 启用 disableMenu 配置
3. 去除内部debug逻辑
4. 增加默认跳转的404页面
## 0.0.6
1. 对于标签属性配置移除id='disable-devtool' 条件,使用 disable-devtool-auto属性
2. 修改readme
## 0.0.5
1. 优化onDevToolOpen事件触发逻辑
## 0.0.4
1. 修改 webpack 打包配置
## 0.0.3
1. 解决alert等原生方法会影响debug计时导致
2. 解决页面且后台会影响debug计时导致
3. 兼容iedisableMenu参数在ie下无效因为ie下右键会阻塞主进程且无法监听
4. 增加config.stopIntervalTime 表示在移动端时取消监视的等待时长
5. 优化判断开发者工具打开的逻辑
## 0.0.2
1. 解决cdn文件无效的bug
## 0.0.1
1. 支持可配置是否禁用右键菜单
2. 禁用 f12 和 ctrl+shift+i 快捷键
3. 支持识别从浏览器菜单栏打开开发者工具并关闭当前页面
4. 开发者可以绕过禁用 (url参数使用tk配合md5加密)
5. 支持几乎所有浏览器
6. 高度可配置
7. 使用极简、体积小巧 (仅7kb)
8. 支持npm引用和script标签引用(属性配置)

View File

@ -1,19 +0,0 @@
import {closeWindow} from './util';
export let config = {
md5: '',
ondevtoolopen: closeWindow, // ondevtoolopen 优先级高于 url
url: '',
tkName: 'ddtk',
interval: 200,
disableMenu: true, // 该参数ie下无效ie 右键菜单会阻塞线程影响debug延迟计算 禁用右键菜单
stopIntervalTime: 5000, // 在移动端时取消监视的等待时长
};
export function mergeConfig (opts = {}) {
for (let k in config) {
if (opts[k] && typeof config[k] === typeof opts[k]) {
config[k] = opts[k];
}
}
}

44
src/detector/detector.ts Normal file
View File

@ -0,0 +1,44 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 22:10:25
* @Description: Coding something
*/
import {closeWindow} from 'src/utils/close-window';
import {config} from 'src/utils/config';
import {DetectorType} from 'src/utils/enum';
import {clearDDInterval, clearDDTimeout, registInterval} from 'src/utils/interval';
import {markDevToolOpenState} from 'src/utils/open-state';
export interface IDetectorConfig {
type: DetectorType;
enabled?: boolean;
}
export abstract class Detector {
type: DetectorType = DetectorType.Unknown;
enabled: boolean = true;
constructor ({
type, enabled = true
}: IDetectorConfig) {
this.type = type;
this.enabled = enabled;
if (this.enabled) {
registInterval(this);
this.init();
}
}
onDevToolOpen () {
console.warn(`You don't have permission to use DEVTOOL!【type = ${this.type}`);
if (config.clearIntervalWhenDevOpenTrigger) {
clearDDInterval();
}
clearDDTimeout();
config.ondevtoolopen(this.type, closeWindow);
markDevToolOpenState(this.type);
}
init () {};
abstract detect (time: number): void;
}

40
src/detector/index.ts Normal file
View File

@ -0,0 +1,40 @@
/*
* @Author: theajack
* @Date: 2021-07-24 23:16:34
* @LastEditor: theajack
* @LastEditTime: 2022-09-28 21:15:17
* @Description: Coding something
*/
import {config} from '../utils/config';
import RegToStringDetector from './sub-detector/reg-to-string';
import DefineIdDetector from './sub-detector/define-id';
import SizeDetector from './sub-detector/size';
import DateToStringDetector from './sub-detector/date-to-string';
import FuncToStringDetector from './sub-detector/func-to-string';
import DebuggerDetector from './sub-detector/debugger';
import PerformanceDetector from './sub-detector/performance';
import DebugLibDetector from './sub-detector/debug-lib';
import {DetectorType} from '../utils/enum';
const Detectors = {
[DetectorType.RegToString]: RegToStringDetector,
[DetectorType.DefineId]: DefineIdDetector,
[DetectorType.Size]: SizeDetector,
[DetectorType.DateToString]: DateToStringDetector,
[DetectorType.FuncToString]: FuncToStringDetector,
[DetectorType.Debugger]: DebuggerDetector,
[DetectorType.Performance]: PerformanceDetector,
[DetectorType.DebugLib]: DebugLibDetector,
};
export function initDetectors () {
const typeArray = config.detectors === 'all' ?
Object.keys(Detectors) : config.detectors;
typeArray.forEach(type => {
const DetectorClass = Detectors[type as Exclude<DetectorType, DetectorType.Unknown>];
new DetectorClass();
});
}

View File

@ -0,0 +1,41 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 23:05:40
* @Description: Coding something
*/
import {clearLog, log} from '../../utils/log';
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {IS} from 'src/utils/util';
export default class extends Detector {
date: Date;
count: 0;
constructor () {
super({
type: DetectorType.DateToString,
enabled: !IS.iosChrome && !IS.iosEdge, // iosChrome 中会有bug
});
}
init () {
this.count = 0;
this.date = new Date();
this.date.toString = () => {
this.count ++;
return '';
};
}
detect () {
this.count = 0;
log(this.date);
clearLog();
if (this.count >= 2) {
this.onDevToolOpen();
}
}
}

View File

@ -0,0 +1,33 @@
/*
* @Author: tackchen
* @Date: 2022-09-28 20:56:01
* @Description:
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
export default class extends Detector {
constructor () {
super({
type: DetectorType.DebugLib
});
}
init () {}
detect () {
if (
// eruda 检测
(window as any).eruda?._devTools?._isShow === true ||
// vconsole 检测
(!!(window as any)._vcOrigConsole && !!window.document.querySelector('#__vconsole.vc-toggle'))
) {
this.onDevToolOpen();
}
}
static isUsing () {
return !!(window as any).eruda || !!(window as any)._vcOrigConsole;
}
}

View File

@ -0,0 +1,30 @@
/*
* @Author: tackchen
* @Date: 2021-11-15 22:26:57
/*
* @Author: tackchen
* @Date: 2022-09-27 23:05:40
* @Description: Coding something
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {now, IS} from 'src/utils/util';
export default class extends Detector {
constructor () {
super({
type: DetectorType.Debugger,
enabled: IS.iosChrome || IS.iosEdge,
});
}
detect () {
const date = now();
(() => {debugger;})();
if (now() - date > 100) {
this.onDevToolOpen();
}
}
}

View File

@ -0,0 +1,38 @@
/*
* @Author: tackchen
* @Date: 2021-11-15 22:26:57
/*
* @Author: tackchen
* @Date: 2022-09-27 23:05:40
* @Description: Coding something
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {log} from 'src/utils/log';
export default class extends Detector {
div: HTMLElement;
constructor () {
super({
type: DetectorType.DefineId,
});
}
init () {
this.div = document.createElement('div');
(this.div as any).__defineGetter__('id', () => {
this.onDevToolOpen();
});
Object.defineProperty(this.div, 'id', {
get: () => {
this.onDevToolOpen();
},
});
}
detect () {
log(this.div);
}
}

View File

@ -0,0 +1,43 @@
/*
* @Author: tackchen
* @Date: 2021-11-15 22:26:57
* @LastEditors: Please set LastEditors
* @LastEditTime: 2023-02-17 22:08:31
* @FilePath: /disable-devtool/src/detector/func-to-string.js
* @Description: Coding something
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {clearLog, log} from 'src/utils/log';
import {IS} from 'src/utils/util';
export default class extends Detector {
count: number;
func: Function;
constructor () {
super({
type: DetectorType.FuncToString,
enabled: (!IS.iosChrome && !IS.iosEdge),
});
}
init () {
this.count = 0;
this.func = () => {};
this.func.toString = () => {
this.count ++;
return '';
};
}
detect () {
this.count = 0;
log(this.func);
clearLog();
if (this.count >= 2) {
this.onDevToolOpen();
}
}
}

View File

@ -0,0 +1,42 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 20:23:12
* @Description: Coding something
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {clearLog, log, table} from 'src/utils/log';
import {calculateTime, IS, createLargeObjectArray} from 'src/utils/util';
export default class extends Detector {
largeObjectArray: any;
maxPrintTime: number;
constructor () {
super({
type: DetectorType.Performance,
enabled: IS.chrome || !IS.mobile
});
}
init () {
this.maxPrintTime = 0;
this.largeObjectArray = createLargeObjectArray();
}
detect () {
const tablePrintTime = calculateTime(() => {table(this.largeObjectArray);});
const logPrintTime = calculateTime(() => {log(this.largeObjectArray);});
this.maxPrintTime = Math.max(this.maxPrintTime, logPrintTime);
clearLog();
if (tablePrintTime === 0 || this.maxPrintTime === 0) return false;
if (tablePrintTime > this.maxPrintTime * 10) {
this.onDevToolOpen();
}
}
};

View File

@ -0,0 +1,45 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 20:23:12
* @Description: Coding something
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {log} from 'src/utils/log';
import {IS} from 'src/utils/util';
export default class extends Detector {
lastTime: number;
reg: RegExp;
constructor () {
super({
type: DetectorType.RegToString,
enabled: (IS.qqBrowser || IS.firefox),
});
}
init () {
this.lastTime = 0;
this.reg = /./;
log(this.reg);
this.reg.toString = () => {
if (IS.qqBrowser) { // ! qq浏览器在控制台没有打开的时候也会触发 打开的时候会连续触发两次 使用这个来判断
const time = new Date().getTime();
if (this.lastTime && time - this.lastTime < 100) {
this.onDevToolOpen();
} else {
this.lastTime = time;
}
} else if (IS.firefox) {
this.onDevToolOpen();
}
return '';
};
}
detect () {
log(this.reg);
}
};

View File

@ -0,0 +1,66 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 20:23:12
* @Description: Coding something
*/
import {Detector} from '../detector';
import {DetectorType} from 'src/utils/enum';
import {IS} from 'src/utils/util';
import {clearDevToolOpenState} from 'src/utils/open-state';
export default class extends Detector {
constructor () {
super({
type: DetectorType.Size,
enabled: (!IS.iframe && !IS.edge)
});
}
init () {
this.checkWindowSizeUneven();
window.addEventListener('resize', () => {
setTimeout(() => {
this.checkWindowSizeUneven();
}, 100);
}, true);
}
detect () {
}
private checkWindowSizeUneven () {
const screenRatio = countScreenZoomRatio();
if (screenRatio === false) { // 如果获取不到屏幕缩放尺寸 则不启用sizeDetector
return true;
}
const widthUneven = window.outerWidth - window.innerWidth * screenRatio > 200; // 调大一点防止误伤
const heightUneven = window.outerHeight - window.innerHeight * screenRatio > 300; // 调大一点防止误伤
if (widthUneven || heightUneven) {
this.onDevToolOpen();
return false;
}
clearDevToolOpenState(this.type);
return true;
}
};
function countScreenZoomRatio () {
if (checkExist(window.devicePixelRatio)) {
return window.devicePixelRatio;
}
const screen = window.screen as any;
if (checkExist(screen)) {
return false;
}
if (screen.deviceXDPI && screen.logicalXDPI) {
return screen.deviceXDPI / screen.logicalXDPI;
}
return false;
};
function checkExist (v: any) {
return typeof v !== 'undefined' && v !== null;
}

18
src/index.d.ts vendored
View File

@ -1,18 +0,0 @@
declare interface optionStatic {
md5?: string; // 绕过禁用的md5值详情见3.2,默认不启用绕过禁用
url?: string; // 关闭页面失败时的跳转页面默认值为localhost
tkName?: string; // 绕过禁用时的url参数名称默认为 ddtk
ondevtoolopen?(): void; // 开发者面板打开的回调启用时url参数无效
interval?: number; // 定时器的时间间隔 默认200ms
disableMenu?: boolean; // 是否禁用右键菜单 默认为true
stopIntervalTime?: number; // 在移动端时取消监视的等待时长
}
declare interface DDTStatic {
(option?: optionStatic): void;
md5(text?: string): string;
version: string;
}
declare const ddt: DDTStatic;
export default ddt;

View File

@ -1,37 +0,0 @@
import {config} from './config';
import {hackAlert, isPC, onPageShowHide} from './util';
let interval = null, timer = null;
let calls = [];
export function initInterval () {
let _pause = false;
let pause = () => {_pause = true;};
let goon = () => {_pause = false;};
hackAlert(pause, goon); // 防止 alert等方法触发了debug延迟计算
onPageShowHide(goon, pause); // 防止切后台触发了debug延迟计算
interval = window.setInterval(() => {
if (_pause) return;
calls.forEach(fn => {fn();});
}, config.interval);
// 两秒之后判断 如果不是pc去掉定时器interval为了优化移动端的性能
// 如果控制面板被打开了该定时器timer会被清除
timer = setTimeout(() => {
if (!isPC()) {
clearInterval();
}
}, config.stopIntervalTime);
}
export function registInterval (fn) {
calls.push(fn);
}
export function clearInterval () {
window.clearInterval(interval);
}
export function clearTimeout () {
window.clearTimeout(timer);
}

View File

@ -1,22 +0,0 @@
import {config} from './config';
export function disableKeyAndMenu () {
window.addEventListener('keydown', (e) => {
e = e || window.event;
let keyCode = e.keyCode || e.which;
// alert(e.keyCode);
if (keyCode === 123 || (e.shiftKey && e.ctrlKey && e.keyCode === 73)) {
e.returnValue = false;
e.preventDefault();
return false;
}
}, false);
if (config.disableMenu) {
window.addEventListener('contextmenu', (e) => {
e = e || window.event;
e.returnValue = false;
e.preventDefault();
return false;
}, false);
}
}

View File

@ -1,100 +0,0 @@
import {disableKeyAndMenu} from './key-menu';
import {initInterval, registInterval, clearTimeout} from './interval';
import {formatName, getUrlParam, isFirefox, isQQBrowser} from './util';
import {mergeConfig, config} from './config';
import md5 from './md5';
import version from './version';
export function disableDevtool (opts) {
mergeConfig(opts);
if (checkTk()) {return;}
initInterval();
disableKeyAndMenu();
initDevTool();
}
disableDevtool.md5 = md5;
disableDevtool.version = version;
let hasOpened = false;
export function onDevToolOpen () {
let time = new Date().getTime();
console.log('You ar not allow to use DEVTOOL!', time);
if (hasOpened) {return {time, next () {}};}
if (!isQQBrowser()) {
hasOpened = true;
}
return {time, next () {
hasOpened = true;
clearTimeout();
config.ondevtoolopen();
}};
}
function checkTk () {
if (config.md5) { // 启用了 md5
let tk = getUrlParam(config.tkName);
if (md5(tk) === config.md5) { // 命中tk
return true;
}
}
return false;
}
function initDevTool () {
const isQQ = isQQBrowser();
const isFF = isFirefox();
let toTest = '';
if (isQQ) {
let lastTime = 0;
toTest = /./;
console.log(toTest);
toTest.toString = function () {
let {time, next} = onDevToolOpen();
if (lastTime && time - lastTime < 100) {
next();
} else {
lastTime = time;
}
return '';
};
} else if (isFF) {
toTest = /./;
console.log(toTest);
toTest.toString = function () {
onDevToolOpen().next();
return '';
};
} else {
toTest = new Image();
toTest.__defineGetter__('id', function () {
onDevToolOpen().next();
});
}
registInterval(() => {
console.log(toTest);
console.clear();
});
}
function checkScriptUse () {
let dom = document.querySelector('[disable-devtool-auto]');
if (!dom) {
return;
}
let json = {};
['md5', 'url', 'tk-name', 'interval', 'disable-menu'].forEach(name => {
let value = dom.getAttribute(name);
if (value !== null) {
if (name === 'interval') {
value = parseInt(value);
} else if (name === 'disable-menu') {
value = value === 'false' ? false : true;
}
json[formatName(name)] = value;
}
});
disableDevtool(json);
}
checkScriptUse();

54
src/main.ts Normal file
View File

@ -0,0 +1,54 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 22:49:01
* @Description: Coding something
*/
import './utils/log';
import {disableKeyAndMenu} from './utils/key-menu';
import {initInterval} from './utils/interval';
import {getUrlParam, initIS, IS} from './utils/util';
import {mergeConfig, config} from './utils/config';
import md5 from './utils/md5';
import version from './version';
import {initDetectors} from './detector/index';
import {DetectorType} from './utils/enum';
import {isDevToolOpened} from './utils/open-state';
import {IConfig, IDisableDevtool} from './type';
import {initLogs} from './utils/log';
import {checkScriptUse} from './plugins/script-use';
export const disableDevtool: IDisableDevtool = Object.assign(((opts?: Partial<IConfig>) => {
const r = (reason = '') => ({success: !reason, reason});
if (disableDevtool.isRunning) return r('already running');
initIS(); // ! 首先初始化env
initLogs(); // 然后初始化log
mergeConfig(opts);
// 被 token 绕过 或者
if (checkTk()) return r('token passed');
// 开启了保护seo 并且 是seobot
if ((config.seo && IS.seoBot)) return r('seobot');
disableDevtool.isRunning = true;
initInterval(disableDevtool);
disableKeyAndMenu(disableDevtool);
initDetectors();
return r();
}), {
isRunning: false,
isSuspend: false,
md5,
version,
DetectorType,
isDevToolOpened,
});
function checkTk () {
if (!config.md5) return false;
// 启用了 md5
const tk = getUrlParam(config.tkName);
return md5(tk) === config.md5; // 命中tk
}
const options = checkScriptUse();
if (options) {
disableDevtool(options);
}

View File

@ -1,198 +0,0 @@
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_md5 (s) { return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length
*/
function core_md5 (x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn (q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
}
function md5_ff (a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg (a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh (a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii (a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add (x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bit_rol (num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert a string to an array of little-endian words
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl (str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
return bin;
}
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex (binarray)
{
var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef';
var str = '';
for (var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 )) & 0xF);
}
return str;
}
export default hex_md5;

42
src/plugins/ignore.ts Normal file
View File

@ -0,0 +1,42 @@
/*
* @Author: chenzhongsheng
* @Date: 2023-02-15 22:36:17
* @Description: Coding something
*/
import {config} from '../utils/config';
let lastUrl = '';
let lastIgnored = false;
export function isIgnored () {
const {ignore} = config;
if (!ignore) return false;
if (typeof ignore === 'function') {
return ignore();
}
if (ignore.length === 0) return false;
const href = location.href;
if (lastUrl === href) return lastIgnored;
lastUrl = href;
let result = false;
for (const item of ignore) {
if (typeof item === 'string') {
if (href.indexOf(item) !== -1) {
result = true;
break;
}
} else {
if (item.test(href)) {
result = true;
break;
}
}
}
lastIgnored = result;
return result;
}

59
src/plugins/script-use.ts Normal file
View File

@ -0,0 +1,59 @@
/*
* @Author: chenzhongsheng
* @Date: 2023-02-17 22:37:16
* @Description: Coding something
*/
export function checkScriptUse () {
if ('undefined' === typeof window || !window.document) return null;
const dom = document.querySelector('[disable-devtool-auto]');
if (!dom) {
return null;
}
const boolAttrs = [
'disable-menu', 'disable-select', 'disable-copy',
'disable-cut', 'disable-paste', 'clear-log'
];
const intAttrs = ['interval'];
const json: Record<string, any> = {};
[
'md5', 'url', 'tk-name', 'detectors',
...boolAttrs, ...intAttrs
].forEach(name => {
let value: any = dom.getAttribute(name);
if (value !== null) {
if (intAttrs.indexOf(name) !== -1) {
value = parseInt(value);
} else if (boolAttrs.indexOf(name) !== -1) {
value = value === 'false' ? false : true;
} else if (name === 'detector') {
if (value !== 'all') {
value = value.split(' ');
}
}
json[formatName(name)] = value;
}
});
return json;
}
function formatName (name: string) {
if (name.indexOf('-') === -1) {
return name;
}
let flag = false;
return name.split('').map(c => {
if (c === '-') {
flag = true;
return '';
}
if (flag) {
flag = false;
return c.toUpperCase();
}
return c;
}).join('');
}

40
src/type.d.ts vendored Normal file
View File

@ -0,0 +1,40 @@
/*
* @Author: chenzhongsheng
* @Date: 2023-02-15 22:38:19
* @Description: Coding something
*/
import {DetectorType} from './utils/enum';
export interface IConfig {
md5: string; // 绕过禁用的md5值详情见3.2,默认不启用绕过禁用
url: string; // 关闭页面失败时的跳转页面默认值为localhost
timeOutUrl: string; // 关闭页面超时跳转的url
tkName: string; // 绕过禁用时的url参数名称默认为 ddtk
ondevtoolopen(type: DetectorType, next: Function): void; // 开发者面板打开的回调启用时url参数无效
ondevtoolclose: Function | null;
interval: number; // 定时器的时间间隔 默认200ms
disableMenu: boolean; // 是否禁用右键菜单 默认为true
stopIntervalTime: number; // 在移动端时取消监视的等待时长
clearIntervalWhenDevOpenTrigger: boolean; // 是否在触发之后停止监控
detectors: DetectorType[] | 'all'; // 启用的监测器 默认为全部
clearLog: boolean; // 是否每次都清除log
disableSelect: boolean; // 是否禁用选择文本 默认为false
disableCopy: boolean; // 是否禁用复制 默认为false
disableCut: boolean; // 是否禁用剪切 默认为false
disablePaste: boolean; // 是否禁用粘贴 默认为false
ignore: (string|RegExp)[] | null | (()=>boolean); // 某些情况忽略禁用
disableIframeParents: boolean; // iframe中是否禁用所有父窗口默认 true
seo: boolean; // 是否启用对seo进行保护默认 true
rewriteHTML: string; // 检测到打开之后重写页面
}
export interface IDisableDevtool {
(opts?: Partial<IConfig>): {success:boolean, reason:string};
isRunning: boolean;
isSuspend: boolean;
md5: (v: string) => string;
version: string;
DetectorType: typeof DetectorType;
isDevToolOpened: ()=>boolean;
}

View File

@ -1,148 +0,0 @@
import {config} from './config';
export function isPC () {
return !/(iphone|ipad|ipod|ios|android)/i.test(navigator.userAgent.toLowerCase());
}
export function closeWindow () {
// 需要是有js跳转到这个页面才可以关闭这个页面
if (config.url) {
window.location.href = config.url;
} else {
try {
window.opener = null;
window.open('', '_self');
window.close();
window.history.back();
} catch (e) {
console.log(e);
}
setTimeout(() => {
window.location.href = `https://tackchen.gitee.io/404.html?h=${encodeURIComponent(location.host)}`;
}, 500);
}
// 否则执行跳转到 url
}
export function getNowTime () {
return new Date().getTime();
}
export function getUrlParam (name) {
let search = window.location.search;
if (search !== '') {
let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
let r = search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
}
return '';
}
export function formatName (name) {
if (name.indexOf('-') === -1) {
return name;
}
var flag = false;
return name.split('').map(c => {
if (c === '-') {
flag = true;
return '';
}
if (flag) {
flag = false;
return c.toUpperCase();
}
return c;
}).join('');
}
export function onPageShowHide (onshow, onhide) {
var hidden, state, visibilityChange;
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
state = 'visibilityState';
} else if (typeof document.mozHidden !== 'undefined') {
hidden = 'mozHidden';
visibilityChange = 'mozvisibilitychange';
state = 'mozVisibilityState';
} else if (typeof document.msHidden !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
state = 'msVisibilityState';
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
state = 'webkitVisibilityState';
}
var cb = function () {
if (document[state] === hidden) {
onhide();
} else {
onshow();
}
};
document.removeEventListener(visibilityChange, cb, false);
document.addEventListener(visibilityChange, cb, false);
}
export function hackAlert (before, after) {
let _alert = window.alert;
let _confirm = window.confirm;
let _prompt = window.prompt;
let mod = (fn) => {
return (...args) => {
if (before) {before();}
fn(...args);
if (after) {after();}
};
};
window.alert = mod(_alert);
window.confirm = mod(_confirm);
window.prompt = mod(_prompt);
}
export function isIE () {
var userAgent = navigator.userAgent; // 取得浏览器的userAgent字符串
var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; // 判断是否IE<11浏览器
var isEdge = userAgent.indexOf('Edge') > -1 && !isIE; // 判断是否IE的Edge浏览器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
return isIE || isEdge || isIE11;
// if (isIE) {
// var reIE = new RegExp('MSIE (\\d+\\.\\d+);');
// reIE.test(userAgent);
// var fIEVersion = parseFloat(RegExp['$1']);
// if (fIEVersion == 7) {
// return 7;
// } else if (fIEVersion == 8) {
// return 8;
// } else if (fIEVersion == 9) {
// return 9;
// } else if (fIEVersion == 10) {
// return 10;
// } else {
// return 6;// IE版本<=7
// }
// } else if (isEdge) {
// return 'edge';// edge
// } else if (isIE11) {
// return 11; // IE11
// } else {
// return -1;// 不是ie浏览器
// }
}
export function isQQBrowser () {
return hasUaName('qqbrowser');
}
export function isFirefox () {
return hasUaName('firefox');
}
function hasUaName (name) {
return navigator.userAgent.toLocaleLowerCase().indexOf(name) !== -1;
}

38
src/utils/close-window.ts Normal file
View File

@ -0,0 +1,38 @@
/*
* @Author: tackchen
* @Date: 2021-12-24 15:14:06
* @LastEditors: Please set LastEditors
* @LastEditTime: 2023-12-22 09:57:58
* @FilePath: /disable-devtool/src/close-window.js
* @Description: Coding something
*/
import {config} from './config';
// import {clearDDInterval} from './interval';
export function closeWindow () {
// clearDDInterval();
if (config.url) {
window.location.href = config.url;
} else if (config.rewriteHTML) {
try {
document.documentElement.innerHTML = config.rewriteHTML;
} catch (e) {
// for 'TrustedHTML' assignment
document.documentElement.innerText = config.rewriteHTML;
}
} else {
try {
window.opener = null;
window.open('', '_self');
// 需要是由js跳转到这个页面才可以关闭这个页面
window.close();
window.history.back();
} catch (e) {
console.log(e);
}
setTimeout(() => {
// 否则执行跳转到 url
window.location.href = config.timeOutUrl || `https://theajack.github.io/disable-devtool/404.html?h=${encodeURIComponent(location.host)}`;
}, 500);
}
}

56
src/utils/config.ts Normal file
View File

@ -0,0 +1,56 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 22:16:40
* @Description: Coding something
*/
import {IConfig} from '../type';
import {closeWindow} from './close-window';
export const config: IConfig = {
md5: '',
ondevtoolopen: closeWindow, // ondevtoolopen 优先级高于 url
ondevtoolclose: null, // ondevtoolclose 监听
url: '',
timeOutUrl: '',
tkName: 'ddtk',
interval: 500,
disableMenu: true, // 是否禁用右键菜单
stopIntervalTime: 5000, // 在移动端时取消监视的等待时长
clearIntervalWhenDevOpenTrigger: false, // 是否在触发之后停止监控
detectors: [0, 1, 3, 4, 5, 6, 7], // 'all', ! 默认去掉sizeDetector 因为会误伤
clearLog: true,
disableSelect: false,
disableCopy: false,
disableCut: false,
disablePaste: false,
ignore: null,
disableIframeParents: true,
seo: true,
rewriteHTML: '',
};
const MultiTypeKeys = ['detectors', 'ondevtoolclose', 'ignore'];
export function mergeConfig (opts: Partial<IConfig> = {}) {
for (const key in config) {
const k = key as keyof IConfig;
if (
typeof opts[k] !== 'undefined' &&
(typeof config[k] === typeof opts[k] || MultiTypeKeys.indexOf(k) !== -1)
) {
(config as any)[k] = opts[k];
}
}
checkConfig();
}
function checkConfig () {
if (
typeof config.ondevtoolclose === 'function' &&
config.clearIntervalWhenDevOpenTrigger === true
) {
config.clearIntervalWhenDevOpenTrigger = false;
console.warn('【DISABLE-DEVTOOL】clearIntervalWhenDevOpenTrigger 在使用 ondevtoolclose 时无效');
}
}

17
src/utils/enum.ts Normal file
View File

@ -0,0 +1,17 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 22:10:55
* @Description: Coding something
*/
export enum DetectorType {
Unknown = -1,
RegToString = 0, // 根据正则检测
DefineId, // 根据dom id检测 1
Size, // 根据窗口尺寸检测 2
DateToString, // 根据Date.toString 检测 3
FuncToString, // 根据Function.toString 检测 4
Debugger, // 根据断点检测仅在ios chrome 真机情况下有效 5
Performance, // 根据log大数据性能检测 6
DebugLib, // 检测第三方调试工具
};

54
src/utils/interval.ts Normal file
View File

@ -0,0 +1,54 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 22:16:40
* @Description: Coding something
*/
import {IDisableDevtool} from '../type';
import {Detector} from '../detector/detector';
import {config} from './config';
import {clearLog} from './log';
import {clearDevToolOpenState, checkOnDevClose} from './open-state';
import {hackAlert, IS, onPageShowHide} from './util';
import {isIgnored} from 'src/plugins/ignore';
import DebugLib from 'src/detector/sub-detector/debug-lib';
let interval: any = 0, timer: any = 0;
const calls: Detector[] = [];
let time = 0;
export function initInterval (dd: IDisableDevtool) {
let _pause = false;
const pause = () => {_pause = true;};
const goon = () => {_pause = false;};
hackAlert(pause, goon); // 防止 alert等方法触发了debug延迟计算
onPageShowHide(goon, pause); // 防止切后台触发了debug延迟计算
interval = window.setInterval(() => {
if (dd.isSuspend || _pause || isIgnored()) return;
for (const detector of calls) {
clearDevToolOpenState(detector.type);
detector.detect(time++);
};
clearLog();
checkOnDevClose();
}, config.interval);
// stopIntervalTime 之后判断 如果不是pc去掉定时器interval为了优化移动端的性能
// 如果控制面板被打开了该定时器timer会被清除
timer = setTimeout(() => {
if (!IS.pc && !DebugLib.isUsing()) {
clearDDInterval();
}
}, config.stopIntervalTime);
}
export function registInterval (detector: Detector) {
calls.push(detector);
}
export function clearDDInterval () {
window.clearInterval(interval);
}
export function clearDDTimeout () {
window.clearTimeout(timer);
}

101
src/utils/key-menu.ts Normal file
View File

@ -0,0 +1,101 @@
/*
* @Author: tackchen
* @Date: 2022-09-27 22:16:40
* @Description: Coding something
*/
import {IDisableDevtool} from '../type';
import {isIgnored} from '../plugins/ignore';
import {config} from './config';
import {IS} from './util';
let isSuspend = () => false;
export function disableKeyAndMenu (dd: IDisableDevtool) {
isSuspend = () => dd.isSuspend;
const top = window.top;
let parent = window.parent;
disableTarget(window);
if (!config.disableIframeParents || !top || !parent || top === window) return;
while (parent !== top) {
disableTarget(parent);
parent = parent.parent;
}
disableTarget(top);
}
function disableTarget (target: Window) {
// let key1 = 'shiftKey', key2 = 'ctrlKey';
// 'metaKey'; // mac 的 commond
// 'altKey'; // mac 的 option
const KEY = {J: 74, I: 73, U: 85, S: 83, F12: 123};
// 禁用 ctrl + shift + i/j
const isOpenDevToolKey = IS.macos ?
((e: KeyboardEvent, code: number) => (e.metaKey && e.altKey && (code === KEY.I || code === KEY.J))) :
((e: KeyboardEvent, code: number) => (e.ctrlKey && e.shiftKey && (code === KEY.I || code === KEY.J)));
const isViewSourceCodeKey = IS.macos ?
((e: KeyboardEvent, code: number) => (e.metaKey && e.altKey && code === KEY.U) || (e.metaKey && code === KEY.S)) :
((e: KeyboardEvent, code: number) => (e.ctrlKey && (code === KEY.S || code === KEY.U)));
target.addEventListener('keydown', (e) => {
e = e || target.event;
const keyCode = e.keyCode || e.which;
if (
keyCode === KEY.F12 || // 禁用f12
isOpenDevToolKey(e, keyCode) || // 禁用 ctrl + shift + i
isViewSourceCodeKey(e, keyCode) // 禁用 ctrl + u 和 ctrl + s 查看和保存源码
) {
return preventEvent(target, e);
}
}, true);
disableMenu(target);
disableSelect(target);
disableCopy(target);
disableCut(target);
disablePaste(target);
}
function disableMenu (target: Window) {
if (config.disableMenu) {
target.addEventListener('contextmenu', (e: Event & {pointerType: string}) => {
if (e.pointerType === 'touch') return;
return preventEvent(target, e);
});
}
}
function disableSelect (target: Window) {
if (config.disableSelect) {
addPreventListener(target, 'selectstart');
}
}
function disableCopy (target: Window) {
if (config.disableCopy) {
addPreventListener(target, 'copy');
}
}
function disableCut (target: Window) {
if (config.disableCut) {
addPreventListener(target, 'cut');
}
}
function disablePaste (target: Window) {
if (config.disablePaste) {
addPreventListener(target, 'paste');
}
}
function addPreventListener (target: Window, name: string) {
target.addEventListener(name, (e: Event) => {
return preventEvent(target, e);
});
}
function preventEvent (target: Window, e: Event) {
if (isIgnored() || isSuspend()) return;
e = e || target.event;
e.returnValue = false;
e.preventDefault();
return false;
}

42
src/utils/log.ts Normal file
View File

@ -0,0 +1,42 @@
/*
* @Author: tackchen
* @Date: 2021-12-24 13:18:23
* @Description: Coding something
*/
import {config} from './config';
import {IS} from './util';
const console = window.console || {
log: function () {
return;
},
table: function () {
return;
},
clear: function () {
return;
}
};
export let log: (...data: any[]) => void;
export let table: (...data: any[]) => void;
let clear: () => void;
export function initLogs () {
if (IS.ie) {
// ie 不支持缓存使用 log等方法
log = (...args: any[]) => {return console.log(...args);};
table = (...args: any[]) => {return console.table(...args);};
clear = () => {return console.clear();};
} else {
log = console.log;
table = console.table;
clear = console.clear;
}
}
export function clearLog () {
if (config.clearLog)
clear();
}

198
src/utils/md5.ts Normal file
View File

@ -0,0 +1,198 @@
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
const hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_md5 (s: string) { return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length
*/
function core_md5 (x: any, len: number)
{
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
let a = 1732584193;
let b = -271733879;
let c = -1732584194;
let d = 271733878;
for (let i = 0; i < x.length; i += 16)
{
const olda = a;
const oldb = b;
const oldc = c;
const oldd = d;
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn (q: number, a: any, b: any, x: any, s: any, t: any)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
}
function md5_ff (a: number, b: number, c: number, d: number, x: any, s: number, t: number)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg (a: number, b: number, c: number, d: number, x: any, s: number, t: number)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh (a: number, b: number, c: number, d: number, x: any, s: number, t: number)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii (a: number, b: number, c: number, d: number, x: any, s: number, t: number)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add (x: number, y: number)
{
const lsw = (x & 0xFFFF) + (y & 0xFFFF);
const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bit_rol (num: number, cnt: number)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert a string to an array of little-endian words
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl (str: string)
{
const bin = Array();
const mask = (1 << chrsz) - 1;
for (let i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
return bin;
}
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex (binarray: string | any[])
{
const hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef';
let str = '';
for (let i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 )) & 0xF);
}
return str;
}
export default hex_md5;

47
src/utils/open-state.ts Normal file
View File

@ -0,0 +1,47 @@
/*
* @Author: tackchen
* @Date: 2022-01-05 22:27:40
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-09-28 00:24:14
* @FilePath: /disable-devtool/src/utils/open-state.js
* @Description: Coding something
*/
import {DetectorType} from 'src/utils/enum';
import {config} from './config';
let isLastStateOpenedBool = false;
const OpenState: {
[prop in DetectorType]?: boolean;
} = {};
export function markDevToolOpenState (type: DetectorType) {
OpenState[type] = true;
}
export function clearDevToolOpenState (type: DetectorType) {
OpenState[type] = false;
}
export function isDevToolOpened () {
for (const key in OpenState) {
if (OpenState[key as unknown as DetectorType]) {
isLastStateOpenedBool = true;
return true;
}
}
isLastStateOpenedBool = false;
return false;
}
export function checkOnDevClose () {
if (
typeof config.ondevtoolclose === 'function'
) {
const isLastOpen = isLastStateOpenedBool; // 缓存一下上一次结果
if (!isDevToolOpened() && isLastOpen) {
config.ondevtoolclose();
}
}
}

162
src/utils/util.ts Normal file
View File

@ -0,0 +1,162 @@
export function now () {
return new Date().getTime();
}
export function calculateTime (func: Function) {
const start = now();
func();
return now() - start;
}
export function getUrlParam (name: string) {
let {search} = window.location;
const {hash} = window.location;
// # 在 ? 之前,即 http://localhost/#file?key=value会导致 search 为空。
if (search === '' && hash !== '') {
// 为 search 补上前缀'?',以便后面的逻辑处理不变。
search = `?${hash.split('?')[1]}`;
}
if (search !== '' && search !== undefined) {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
const r = search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
}
return '';
}
export function onPageShowHide (
onshow: ()=>void,
onhide: ()=>void,
) {
const doc = document as any;
let hidden: string, state: string, visibilityChange;
if (typeof doc.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
state = 'visibilityState';
} else if (typeof doc.mozHidden !== 'undefined') {
hidden = 'mozHidden';
visibilityChange = 'mozvisibilitychange';
state = 'mozVisibilityState';
} else if (typeof doc.msHidden !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
state = 'msVisibilityState';
} else if (typeof doc.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
state = 'webkitVisibilityState';
}
const cb = function () {
if (doc[state] === hidden) {
onhide();
} else {
onshow();
}
};
doc.removeEventListener(visibilityChange, cb, false);
doc.addEventListener(visibilityChange, cb, false);
}
export function hackAlert (before?: ()=>void, after?: ()=>void) {
const _alert = window.alert;
const _confirm = window.confirm;
const _prompt = window.prompt;
const mod = (fn: Function) => {
return (...args: any[]) => {
if (before) {before();}
const result = fn(...args);
if (after) {after();}
return result;
};
};
try {
window.alert = mod(_alert);
window.confirm = mod(_confirm);
window.prompt = mod(_prompt);
} catch (e) {
}
}
export const IS = {
iframe: false,
pc: false,
qqBrowser: false,
firefox: false,
macos: false,
edge: false,
oldEdge: false,
ie: false,
iosChrome: false,
iosEdge: false,
chrome: false,
seoBot: false,
mobile: false,
};
export function initIS () {
const ua = navigator.userAgent.toLowerCase();
const has = (name: string) => ua.indexOf(name) !== -1;
const mobile = isMobile();
const iframe = !!window.top && window !== window.top;
const pc = !mobile;
const qqBrowser = has('qqbrowser');
const firefox = has('firefox');
const macos = has('macintosh');
const edge = has('edge');
const oldEdge = edge && !has('chrome');
const ie = oldEdge || has('trident') || has('msie');
const iosChrome = has('crios');
const iosEdge = has('edgios');
const chrome = has('chrome') || iosChrome;
// google lighthouse ua中有 moto g power
const seoBot = !mobile && /(googlebot|baiduspider|bingbot|applebot|petalbot|yandexbot|bytespider|chrome\-lighthouse|moto g power)/i.test(ua);
Object.assign(IS, {
iframe, pc, qqBrowser, firefox, macos, edge, oldEdge,
ie, iosChrome, iosEdge, chrome, seoBot, mobile,
});
}
function isMobileByUa () {
return /(iphone|ipad|ipod|ios|android)/i.test(navigator.userAgent.toLowerCase());
}
function isMobile () {
const {platform, maxTouchPoints} = navigator;
if (typeof maxTouchPoints === 'number') {
return maxTouchPoints > 1;
}
if (typeof platform === 'string') {
const v = platform.toLowerCase();
if (/(mac|win)/i.test(v)) return false;
else if (/(android|iphone|ipad|ipod|arch)/i.test(v)) return true;
}
return isMobileByUa();
}
function createLargeObject () {
const largeObject: Record<string, string> = {};
for (let i = 0; i < 500; i++) {
largeObject[`${i}`] = `${i}`;
}
return largeObject;
}
export function createLargeObjectArray () {
const largeObject = createLargeObject();
const largeObjectArray = [];
for (let i = 0; i < 50; i++) {
largeObjectArray.push(largeObject);
}
return largeObjectArray;
}

View File

@ -1 +0,0 @@
export default '0.1.1';

1
src/version.ts Normal file
View File

@ -0,0 +1 @@
export default '0.3.7';

34
tsconfig.json Normal file
View File

@ -0,0 +1,34 @@
{
"compilerOptions": {
"baseUrl": ".",
"outDir": "output",
"sourceMap": false,
"target": "es2016",
"module": "esnext",
"moduleResolution": "node",
"allowJs": true,
"noUnusedLocals": true,
"strictNullChecks": true,
"noImplicitAny": true,
"noImplicitThis": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"removeComments": false,
"jsx": "preserve",
"lib": ["esnext", "dom"],
"types": ["node"],
"rootDir": ".",
"noEmit": false,
"paths": {}
},
"include": [
".eslintrc.js",
"babel.config.js",
"scripts/**/*",
"src/**/*"
],
"exclude": [
"./node_modules"
]
}

View File

@ -1,26 +0,0 @@
const path = require('path');
require('../helper/copy-to-npm');
require('../helper/copy-version');
require('../helper/mod-index-html-version');
module.exports = {
mode: 'production',
entry: path.resolve('./', 'src/index.js'),
output: {
path: path.resolve('./', 'npm'),
filename: 'disable-devtool.min.js',
library: 'DisableDevtool',
libraryTarget: 'umd',
// umdNamedDefine: true, // 这个地方暂时有问题 打包出来的时 {default: DisableDevtool} 临时解决是直接修改打包后的文件
globalObject: 'this',
libraryExport: 'default',
},
module: {
rules: [{
test: /(.js)$/,
use: [{
loader: 'babel-loader',
}]
}]
}
};

View File

@ -1,32 +0,0 @@
const path = require('path');
module.exports = {
entry: path.resolve('./', 'public/main.js'),
output: {
path: path.resolve('./', 'public'),
filename: 'bundle.js'
},
devtool: 'eval-source-map',
devServer: {
contentBase: path.resolve('./', 'public'),
historyApiFallback: true,
inline: true,
host: 'localhost'// '0.0.0.0' //
},
module: {
rules: [{
test: /(.js)$/,
use: [{
loader: 'babel-loader',
}]
}, {
test: /(.js)$/,
loader: 'eslint-loader',
enforce: 'pre',
exclude: /node_modules/,
options: {
configFile: './.eslintrc.js'
}
}]
}
};