├── iterm-ssh ├── logo.png ├── plugin.json ├── README.md └── preload.js ├── show-hosts ├── logo.png ├── README.md ├── plugin.json └── preload.js ├── iterm-command ├── logo.png ├── README.md ├── plugin.json └── preload.js ├── youdao-translate ├── logo.png ├── plugin.json ├── README.md ├── error_code.js ├── preload.js └── sha256.js ├── README.md └── .gitignore /iterm-ssh/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhan219/utools-plugin/HEAD/iterm-ssh/logo.png -------------------------------------------------------------------------------- /show-hosts/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhan219/utools-plugin/HEAD/show-hosts/logo.png -------------------------------------------------------------------------------- /iterm-command/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhan219/utools-plugin/HEAD/iterm-command/logo.png -------------------------------------------------------------------------------- /youdao-translate/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhan219/utools-plugin/HEAD/youdao-translate/logo.png -------------------------------------------------------------------------------- /show-hosts/README.md: -------------------------------------------------------------------------------- 1 | ## 搜索hosts文件并复制ip到剪粘板 2 | 3 | ### 进入页面显示所有hosts 4 | ![image](https://gitee.com/yhan219/blog-image/raw/master/yhan/image.png) 5 | 6 | ### 输入关键字搜索 7 | ![image_1](https://gitee.com/yhan219/blog-image/raw/master/yhan/image_1.png) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## `utools`插件开发 2 | 3 | - [显示hosts](https://github.com/yhan219/utools-plugin/tree/master/show-hosts) 4 | - [iterm-ssh](https://github.com/yhan219/utools-plugin/tree/master/iterm-ssh) 5 | - [有道翻译](https://github.com/yhan219/utools-plugin/tree/master/youdao-translate) 6 | - [iterm执行命令](https://github.com/yhan219/utools-plugin/tree/master/iterm-command) 7 | 8 | **本人是后端开发,前端基础较差,欢迎拍砖** 9 | -------------------------------------------------------------------------------- /iterm-ssh/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginName": "iTerm执行ssh", 3 | "author": "yhan219", 4 | "homepage": "https://blog.yhan219.com", 5 | "logo": "logo.png", 6 | "preload": "preload.js", 7 | "platform": [ 8 | "darwin" 9 | ], 10 | "features": [ 11 | { 12 | "code": "ssh_hosts", 13 | "explain": "搜索hosts并在iTerm执行ssh", 14 | "cmds":["ssh"] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /show-hosts/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginName": "show hosts", 3 | "description": "搜索hosts并复制到粘贴板", 4 | "author": "yhan219", 5 | "homepage": "https://blog.yhan219.com", 6 | "logo": "logo.png", 7 | "preload": "preload.js", 8 | "features": [ 9 | { 10 | "code": "list_hosts", 11 | "explain": "搜索hosts", 12 | "cmds":["hosts", "list hosts"] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /iterm-command/README.md: -------------------------------------------------------------------------------- 1 | ## iTerm打开终端并执行命令 2 | 3 | 用习惯了alfred的小插件,移植到utools,仅支持mac 4 | 5 | 插件开源地址 [utools-plugin](https://github.com/yhan219/utools-plugin) 6 | 7 | - `>`是直接执行命令 8 | - `.>`当前目录执行命令 9 | 10 | ### 功能介绍 11 | - 进入显示执行命令历史,选中复制到粘贴板,默认保存50条记录 12 | ![Li9StX](https://gitee.com/yhan219/blog-image/raw/master/yhan/Li9StX.png) 13 | - 输入命令执行,输入过程中会提示历史命令 14 | ![u8otFC](https://gitee.com/yhan219/blog-image/raw/master/yhan/u8otFC.png) 15 | - 选中回车即可打开iTerm执行命令,并保存到搜索历史中 16 | ![dv1ogZ](https://gitee.com/yhan219/blog-image/raw/master/yhan/dv1ogZ.png) 17 | 18 | ### 更新历史 19 | - 0.0.3 添加当前目录执行 20 | - 0.0.2 新标签打开并执行命令 21 | -------------------------------------------------------------------------------- /iterm-ssh/README.md: -------------------------------------------------------------------------------- 1 | ## iTerm打开终端并执行命令 2 | 3 | > 本插件仅适用于`mac` 4 | 5 | 作为后端开发,经常需要`ssh`登录到服务器。 6 | 开发此插件,读取`hosts`文件提示到输入框,方便ssh登录 7 | 8 | 插件开源地址 [utools-plugin](https://github.com/yhan219/utools-plugin) 9 | 10 | ### 功能介绍 11 | - 进入显示执行ssh历史及hosts内容,前5条为历史,后面的为hosts文件内容 12 | ![v9UNtJ](https://gitee.com/yhan219/blog-image/raw/master/yhan/v9UNtJ.png) 13 | - 输入并执行命令,输入过程中会提示历史命令及hosts内容,如图,第一条为历史记录,第二条为hosts提示 14 | ![DURqT1](https://gitee.com/yhan219/blog-image/raw/master/yhan/DURqT1.png) 15 | - 选中回车即可打开iTerm登录`ssh`,并保存到搜索历史中 16 | ![pSyA5v](https://gitee.com/yhan219/blog-image/raw/master/yhan/pSyA5v.png) 17 | 18 | ### 更新历史 19 | - 0.0.2 新标签打开 -------------------------------------------------------------------------------- /youdao-translate/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginName": "有道翻译", 3 | "description": "有道搜索翻译并复制到粘贴板", 4 | "author": "yhan219", 5 | "homepage": "https://blog.yhan219.com", 6 | "logo": "logo.png", 7 | "preload": "preload.js", 8 | "features": [ 9 | { 10 | "code": "youdao-translate", 11 | "explain": "有道翻译", 12 | "cmds": [ 13 | "有道", 14 | "翻译", 15 | { 16 | "type": "over", 17 | "label": "有道翻译", 18 | "minLength": 1, 19 | "maxLength": 50 20 | } 21 | ] 22 | }, 23 | { 24 | "code": "youdao-app-id", 25 | "explain": "有道翻译appId设置", 26 | "cmds": [ 27 | "有道appid" 28 | ] 29 | }, 30 | { 31 | "code": "youdao-app-secret", 32 | "explain": "有道翻译app秘钥设置", 33 | "cmds": [ 34 | "有道秘钥" 35 | ] 36 | } 37 | ] 38 | } -------------------------------------------------------------------------------- /youdao-translate/README.md: -------------------------------------------------------------------------------- 1 | ## 有道翻译 2 | 3 | 对于大部分人,搜索结果往往需要直接复制到粘贴板,特此开发了此插件 4 | 5 | 插件开源地址 [utools-plugin](https://github.com/yhan219/utools-plugin) 6 | 7 | ### 功能介绍 8 | - 进入显示搜索历史,选中复制到粘贴板,默认保存20条记录 9 | ![e7EBIu](https://gitee.com/yhan219/blog-image/raw/master/yhan/e7EBIu.png) 10 | - 输入关键字搜索(自动识别中英文) 11 | ![pj8RPP](https://gitee.com/yhan219/blog-image/raw/master/yhan/pj8RPP.jpg) 12 | 13 | - 选中回车即可复制翻译结果,并保存到搜索历史中 14 | 15 | ### 设置 16 | 由于有道翻译需要收费,所以需要用户手动设置appId和秘钥,每个新注册的用户都有50元体验金,对于个人来说已经够用了,即使用完了也可以重新注册个账号。 17 | - 打开网址[有道开放平台](http://ai.youdao.com/login.s) 18 | - 登录成功后,点击`应用管理--我的应用`,没有应用的创建一个即可 19 | - 点击进入应用后即可看到应用id和应用秘钥 20 | - 如图: 21 | ![应用](https://gitee.com/yhan219/blog-image/raw/master/yhan/aLHCYP.png) 22 | - 在utools主窗口输入 `有道appid`,回车进入,再将复制的appId输入即可 23 | - 在utools主窗口输入 `有道秘钥`,回车进入,再将复制的秘钥输入即可 24 | - 如图: 25 | ![wXyw8N](https://gitee.com/yhan219/blog-image/raw/master/yhan/wXyw8N.png) 26 | -------------------------------------------------------------------------------- /iterm-command/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginName": "iTerm执行命令", 3 | "description": "打开iTerm并执行命令", 4 | "author": "yhan219", 5 | "homepage": "https://blog.yhan219.com", 6 | "logo": "logo.png", 7 | "preload": "preload.js", 8 | "platform": [ 9 | "darwin" 10 | ], 11 | "features": [ 12 | { 13 | "code": "iterm_command", 14 | "explain": "打开iterm并执行命令", 15 | "cmds": [ 16 | "iterm", 17 | ">", 18 | { 19 | "type": "over", 20 | "label": "打开iTerm并执行", 21 | "minLength": 2, 22 | "maxLength": 50 23 | } 24 | ] 25 | }, 26 | { 27 | "code": "current_iterm_command", 28 | "explain": "当前目录打开iTerm并执行", 29 | "cmds": [ 30 | "iterm", 31 | ".>", 32 | { 33 | "type": "over", 34 | "label": "当前目录打开iTerm并执行", 35 | "minLength": 2, 36 | "maxLength": 50 37 | } 38 | ] 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### macOS template 3 | # General 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | .com.apple.timemachine.donotpresent 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | ### Windows template 31 | # Windows thumbnail cache files 32 | Thumbs.db 33 | Thumbs.db:encryptable 34 | ehthumbs.db 35 | ehthumbs_vista.db 36 | 37 | # Dump file 38 | *.stackdump 39 | 40 | # Folder config file 41 | [Dd]esktop.ini 42 | 43 | # Recycle Bin used on file shares 44 | $RECYCLE.BIN/ 45 | 46 | # Windows Installer files 47 | *.cab 48 | *.msi 49 | *.msix 50 | *.msm 51 | *.msp 52 | 53 | # Windows shortcuts 54 | *.lnk 55 | 56 | ### Example user template template 57 | ### Example user template 58 | 59 | # IntelliJ project files 60 | .idea 61 | *.iml 62 | out 63 | gen 64 | 65 | -------------------------------------------------------------------------------- /show-hosts/preload.js: -------------------------------------------------------------------------------- 1 | const {clipboard} = require('electron') 2 | const fs = require('fs') 3 | 4 | const noData = [{ 5 | title: '没有数据', 6 | description: '', 7 | icon: './logo.png' 8 | }] 9 | 10 | const noHostsFile = [{ 11 | title: '没有hosts文件,请检查', 12 | description: '', 13 | icon: './logo.png' 14 | }] 15 | 16 | String.prototype.resetBlank = function () { 17 | const regEx = /\s+/g; 18 | return this.replace(regEx, ' '); 19 | }; 20 | 21 | var copyResult = function (itemData) { 22 | if (itemData.description !== '') { 23 | clipboard.writeText(itemData.description, 'selection'); 24 | } 25 | } 26 | 27 | function handleHosts(searchWord, callbackSetList) { 28 | let hostsFilePath 29 | let utools = window.utools; 30 | if (utools.isMacOs() || utools.isLinux()) { 31 | hostsFilePath = "/etc/hosts"; 32 | } else { 33 | hostsFilePath = "C:\\Windows\\System32\\drivers\\etc\\hosts" 34 | } 35 | if (!fs.existsSync(hostsFilePath)) { 36 | callbackSetList(noHostsFile) 37 | return; 38 | } 39 | 40 | const fileData = fs.readFileSync(hostsFilePath, 'utf-8'); 41 | let dataLine = fileData.split(/[(\r\n)\r\n]+/); 42 | 43 | let searchNull = typeof searchWord == null || searchWord === null || searchWord === '' || searchWord === undefined; 44 | 45 | let hostsData = [] 46 | 47 | dataLine.forEach(line => { 48 | if (!line || line.trim().startsWith("#")) { 49 | return 50 | } 51 | let resetBlank = line.trim().resetBlank(); 52 | let split = resetBlank.split(' '); 53 | if (!split || split.length !== 2) { 54 | return 55 | } 56 | if (!searchNull && resetBlank.toLowerCase().indexOf(searchWord.trim().toLowerCase()) < 0) { 57 | return 58 | } 59 | hostsData.push({ 60 | title: split[1], 61 | description: split[0], 62 | icon: './logo.png' 63 | }); 64 | }); 65 | if (hostsData.length === 0) { 66 | callbackSetList(noData) 67 | return 68 | } 69 | callbackSetList(hostsData) 70 | } 71 | 72 | 73 | window.exports = { 74 | "list_hosts": { 75 | mode: "list", 76 | args: { 77 | // 进入插件时调用(可选) 78 | enter: (action, callbackSetList) => { 79 | handleHosts(null, callbackSetList) 80 | }, 81 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 82 | search: (action, searchWord, callbackSetList) => { 83 | handleHosts(searchWord, callbackSetList) 84 | }, 85 | // 用户选择列表中某个条目时被调用 86 | select: (action, itemData, callbackSetList) => { 87 | window.utools.hideMainWindow() 88 | copyResult(itemData) 89 | window.utools.outPlugin() 90 | }, 91 | placeholder: "搜索(搜索结果点击可复制到剪粘板)" 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /youdao-translate/error_code.js: -------------------------------------------------------------------------------- 1 | const errorCode = new Map([ 2 | ['101', '缺少必填的参数,首先确保必填参数齐全,然后确认参数书写是否正确。'], 3 | ['102', '不支持的语言类型'], 4 | ['103', '翻译文本过长'], 5 | ['104', '不支持的API类型'], 6 | ['105', '不支持的签名类型'], 7 | ['106', '不支持的响应类型'], 8 | ['107', '不支持的传输加密类型'], 9 | ['108', '应用ID无效,注册账号,登录后台创建应用和实例并完成绑定,可获得应用ID和应用密钥等信息'], 10 | ['109', 'batchLog格式不正确'], 11 | ['110', '无相关服务的有效实例,应用没有绑定服务实例,可以新建服务实例,绑定服务实例。注:某些服务的翻译结果发音需要tts实例,需要在控制台创建语音合成实例绑定应用后方能使用。'], 12 | ['111', '开发者账号无效'], 13 | ['112', '请求服务无效'], 14 | ['113', 'q不能为空'], 15 | ['114', '不支持的图片传输方式'], 16 | ['116', 'strict字段取值无效,请参考文档填写正确参数值'], 17 | ['201', '解密失败,可能为DES,BASE64,URLDecode的错误'], 18 | ['202', '签名检验失败,如果确认应用ID和应用密钥的正确性,仍返回202,一般是编码问题。请确保翻译文本 q 为UTF-8编码.'], 19 | ['203', '访问IP地址不在可访问IP列表'], 20 | ['205', '请求的接口与应用的平台类型不一致,确保接入方式(Android SDK、IOS SDK、API)与创建的应用平台类型一致。如有疑问请参考入门指南'], 21 | ['206', '因为时间戳无效导致签名校验失败'], 22 | ['207', '重放请求'], 23 | ['301', '辞典查询失败'], 24 | ['302', '翻译查询失败'], 25 | ['303', '服务端的其它异常'], 26 | ['304', '会话闲置太久超时'], 27 | ['401', '账户已经欠费停'], 28 | ['402', 'offlinesdk不可用'], 29 | ['411', '访问频率受限,请稍后访问'], 30 | ['412', '长请求过于频繁,请稍后访问'], 31 | ['1001', '无效的OCR类型'], 32 | ['1002', '不支持的OCR image类型'], 33 | ['1003', '不支持的OCR Language类型'], 34 | ['1004', '识别图片过大'], 35 | ['1201', '图片base64解密失败'], 36 | ['1301', 'OCR段落识别失败'], 37 | ['1411', '访问频率受限'], 38 | ['1412', '超过最大识别字节数'], 39 | ['2003', '不支持的语言识别Language类型'], 40 | ['2004', '合成字符过长'], 41 | ['2005', '不支持的音频文件类型'], 42 | ['2006', '不支持的发音类型'], 43 | ['2201', '解密失败'], 44 | ['2301', '服务的异常'], 45 | ['2411', '访问频率受限,请稍后访问'], 46 | ['2412', '超过最大请求字符数'], 47 | ['3001', '不支持的语音格式'], 48 | ['3002', '不支持的语音采样率'], 49 | ['3003', '不支持的语音声道'], 50 | ['3004', '不支持的语音上传类型'], 51 | ['3005', '不支持的语言类型'], 52 | ['3006', '不支持的识别类型'], 53 | ['3007', '识别音频文件过大'], 54 | ['3008', '识别音频时长过长'], 55 | ['3009', '不支持的音频文件类型'], 56 | ['3010', '不支持的发音类型'], 57 | ['3201', '解密失败'], 58 | ['3301', '语音识别失败'], 59 | ['3302', '语音翻译失败'], 60 | ['3303', '服务的异常'], 61 | ['3411', '访问频率受限,请稍后访问'], 62 | ['3412', '超过最大请求字符数'], 63 | ['4001', '不支持的语音识别格式'], 64 | ['4002', '不支持的语音识别采样率'], 65 | ['4003', '不支持的语音识别声道'], 66 | ['4004', '不支持的语音上传类型'], 67 | ['4005', '不支持的语言类型'], 68 | ['4006', '识别音频文件过大'], 69 | ['4007', '识别音频时长过长'], 70 | ['4201', '解密失败'], 71 | ['4301', '语音识别失败'], 72 | ['4303', '服务的异常'], 73 | ['4411', '访问频率受限,请稍后访问'], 74 | ['4412', '超过最大请求时长'], 75 | ['5001', '无效的OCR类型'], 76 | ['5002', '不支持的OCR image类型'], 77 | ['5003', '不支持的语言类型'], 78 | ['5004', '识别图片过大'], 79 | ['5005', '不支持的图片类型'], 80 | ['5006', '文件为空'], 81 | ['5201', '解密错误,图片base64解密失败'], 82 | ['5301', 'OCR段落识别失败'], 83 | ['5411', '访问频率受限'], 84 | ['5412', '超过最大识别流量'], 85 | ['9001', '不支持的语音格式'], 86 | ['9002', '不支持的语音采样率'], 87 | ['9003', '不支持的语音声道'], 88 | ['9004', '不支持的语音上传类型'], 89 | ['9005', '不支持的语音识别 Language类型'], 90 | ['9301', 'ASR识别失败'], 91 | ['9303', '服务器内部错误'], 92 | ['9411', '访问频率受限(超过最大调用次数)'], 93 | ['9412', '超过最大处理语音长度'], 94 | ['10001', '无效的OCR类型'], 95 | ['10002', '不支持的OCR image类型'], 96 | ['10004', '识别图片过大'], 97 | ['10201', '图片base64解密失败'], 98 | ['10301', 'OCR段落识别失败'], 99 | ['10411', '访问频率受限'], 100 | ['10412', '超过最大识别流量'], 101 | ['11001', '不支持的语音识别格式'], 102 | ['11002', '不支持的语音识别采样率'], 103 | ['11003', '不支持的语音识别声道'], 104 | ['11004', '不支持的语音上传类型'], 105 | ['11005', '不支持的语言类型'], 106 | ['11006', '识别音频文件过大'], 107 | ['11007', '识别音频时长过长,最大支持30s'], 108 | ['11201', '解密失败'], 109 | ['11301', '语音识别失败'], 110 | ['11303', '服务的异常'], 111 | ['11411', '访问频率受限,请稍后访问'], 112 | ['11412', '超过最大请求时长'], 113 | ['12001', '图片尺寸过大'], 114 | ['12002', '图片base64解密失败'], 115 | ['12003', '引擎服务器返回错误'], 116 | ['12004', '图片为空'], 117 | ['12005', '不支持的识别图片类型'], 118 | ['12006', '图片无匹配结果'], 119 | ['13001', '不支持的角度类型'], 120 | ['13002', '不支持的文件类型'], 121 | ['13003', '表格识别图片过大'], 122 | ['13004', '文件为空'], 123 | ['13301', '表格识别失败'], 124 | ['15001', '需要图片'], 125 | ['15002', '图片过大(1M)'], 126 | ['15003', '服务调用失败'], 127 | ['17001', '需要图片'], 128 | ['17002', '图片过大(1M)'], 129 | ['17003', '识别类型未找到'], 130 | ['17004', '不支持的识别类型'], 131 | ['17005', '服务调用失败'] 132 | ]); 133 | module.exports = { 134 | errorCode 135 | } -------------------------------------------------------------------------------- /iterm-command/preload.js: -------------------------------------------------------------------------------- 1 | function dateFormat(fmt, date) { 2 | let ret; 3 | const opt = { 4 | "Y+": date.getFullYear().toString(), // 年 5 | "m+": (date.getMonth() + 1).toString(), // 月 6 | "d+": date.getDate().toString(), // 日 7 | "H+": date.getHours().toString(), // 时 8 | "M+": date.getMinutes().toString(), // 分 9 | "S+": date.getSeconds().toString() // 秒 10 | // 有其他格式化字符需求可以继续添加,必须转化成字符串 11 | }; 12 | for (let k in opt) { 13 | ret = new RegExp("(" + k + ")").exec(fmt); 14 | if (ret) { 15 | fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) 16 | } 17 | } 18 | return fmt; 19 | } 20 | 21 | const saveOrUpdateDb = function (key, data) { 22 | if (!data) { 23 | return 24 | } 25 | let keyData = window.utools.db.get(key); 26 | if (!keyData) { 27 | window.utools.db.put({ 28 | _id: key, 29 | data: data 30 | }) 31 | return 32 | } 33 | utools.db.put({ 34 | _id: key, 35 | data: data, 36 | _rev: keyData._rev 37 | }) 38 | }; 39 | 40 | const addHistory = item => { 41 | if (!item) { 42 | return 43 | } 44 | let title = item.title; 45 | item.description = dateFormat("mm-dd HH:MM:SS", new Date()) 46 | 47 | let history = getHistory() || []; 48 | let index = -1; 49 | for (let i = 0; i < history.length; i++) { 50 | if (history[i].title === title) { 51 | index = i; 52 | } 53 | } 54 | if (index !== -1) { 55 | history.splice(index, 1); 56 | } 57 | history.unshift(item); 58 | if (history.length > 50) { 59 | history = history.slice(0, 50); 60 | } 61 | saveOrUpdateDb('history', history); 62 | }; 63 | 64 | const getHistory = function () { 65 | let history = window.utools.db.get("history"); 66 | if (history) { 67 | return history.data 68 | } 69 | return history; 70 | } 71 | 72 | const handleSearch = function (searchWord, callbackSetList) { 73 | let items = getHistory()||[]; 74 | if (searchWord) { 75 | items = items.filter(item => item.title.indexOf(searchWord) !== -1); 76 | items.unshift({ 77 | title: searchWord 78 | }); 79 | } 80 | if (items.length !== 0) { 81 | callbackSetList(items) 82 | } 83 | }; 84 | 85 | const execCommand = function (itemData,path) { 86 | if (!itemData || !itemData.title) { 87 | return 88 | } 89 | let goPath = path ? 'tell current session to write text "cd "& quoted form of "' + path + '"' : ''; 90 | require('child_process').exec(`osascript -e 'tell application "iTerm" 91 | activate 92 | try 93 | select current window 94 | tell current window 95 | create tab with default profile 96 | end tell 97 | tell current window 98 | ${goPath} 99 | tell current session to write text "${itemData.title}" 100 | end tell 101 | on error 102 | select current window 103 | tell current window 104 | ${goPath} 105 | tell current session to write text "${itemData.title}" 106 | end tell 107 | end try 108 | end tell'`, (error, stdout, stderr) => { 109 | if (error) return window.utools.showNotification(stderr) 110 | window.utools.outPlugin() 111 | }); 112 | addHistory(itemData) 113 | }; 114 | 115 | window.exports = { 116 | "iterm_command": { 117 | mode: "list", 118 | args: { 119 | // 进入插件时调用(可选) 120 | enter: (action, callbackSetList) => { 121 | if (action.type === 'over' && action.payload) { 122 | // 直接调用setSubInputValue不生效,特殊处理 123 | setTimeout(function () { 124 | window.utools.setSubInputValue(action.payload); 125 | }, 50); 126 | } else { 127 | let history = getHistory(); 128 | if (history) { 129 | callbackSetList(history) 130 | } 131 | } 132 | 133 | }, 134 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 135 | search: (action, searchWord, callbackSetList) => { 136 | handleSearch(searchWord, callbackSetList) 137 | }, 138 | // 用户选择列表中某个条目时被调用 139 | select: (action, itemData, callbackSetList) => { 140 | window.utools.hideMainWindow() 141 | execCommand(itemData) 142 | window.utools.outPlugin() 143 | }, 144 | placeholder: "回车执行" 145 | } 146 | }, 147 | "current_iterm_command": { 148 | mode: "list", 149 | args: { 150 | // 进入插件时调用(可选) 151 | enter: (action, callbackSetList) => { 152 | if (action.type === 'over' && action.payload) { 153 | // 直接调用setSubInputValue不生效,特殊处理 154 | setTimeout(function () { 155 | window.utools.setSubInputValue(action.payload); 156 | }, 50); 157 | } else { 158 | let history = getHistory(); 159 | if (history) { 160 | callbackSetList(history) 161 | } 162 | } 163 | 164 | }, 165 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 166 | search: (action, searchWord, callbackSetList) => { 167 | handleSearch(searchWord, callbackSetList) 168 | }, 169 | // 用户选择列表中某个条目时被调用 170 | select: (action, itemData, callbackSetList) => { 171 | window.utools.hideMainWindow() 172 | execCommand(itemData,window.utools.getCurrentFolderPath() || '~') 173 | window.utools.outPlugin() 174 | }, 175 | placeholder: "回车当前目录执行" 176 | } 177 | } 178 | } -------------------------------------------------------------------------------- /iterm-ssh/preload.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const noHostsFile = { 4 | description: '没有hosts文件,请检查' 5 | } 6 | 7 | String.prototype.resetBlank = function () { 8 | var regEx = /\s+/g; 9 | return this.replace(regEx, ' '); 10 | }; 11 | 12 | String.prototype.endWith = function (s) { 13 | var d = this.length - s.length; 14 | return (d >= 0 && this.lastIndexOf(s) == d) 15 | } 16 | 17 | 18 | function dateFormat(fmt, date) { 19 | let ret; 20 | const opt = { 21 | "Y+": date.getFullYear().toString(), // 年 22 | "m+": (date.getMonth() + 1).toString(), // 月 23 | "d+": date.getDate().toString(), // 日 24 | "H+": date.getHours().toString(), // 时 25 | "M+": date.getMinutes().toString(), // 分 26 | "S+": date.getSeconds().toString() // 秒 27 | // 有其他格式化字符需求可以继续添加,必须转化成字符串 28 | }; 29 | for (let k in opt) { 30 | ret = new RegExp("(" + k + ")").exec(fmt); 31 | if (ret) { 32 | fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) 33 | } 34 | } 35 | return fmt; 36 | } 37 | 38 | 39 | const saveOrUpdateDb = function (key, data) { 40 | if (!data) { 41 | return 42 | } 43 | let keyData = window.utools.db.get(key); 44 | if (!keyData) { 45 | window.utools.db.put({ 46 | _id: key, 47 | data: data 48 | }) 49 | return 50 | } 51 | utools.db.put({ 52 | _id: key, 53 | data: data, 54 | _rev: keyData._rev 55 | }) 56 | }; 57 | 58 | const addHistory = item => { 59 | if (!item) { 60 | return 61 | } 62 | let title = item.title; 63 | item.description = dateFormat("mm-dd HH:MM:SS", new Date()) 64 | 65 | let history = getHistory() || []; 66 | let index = -1; 67 | for (let i = 0; i < history.length; i++) { 68 | if (history[i].title === title) { 69 | index = i; 70 | } 71 | } 72 | if (index !== -1) { 73 | history.splice(index, 1); 74 | } 75 | history.unshift(item); 76 | if (history.length > 5) { 77 | history = history.slice(0, 5); 78 | } 79 | saveOrUpdateDb('history', history); 80 | }; 81 | 82 | const getHistory = function () { 83 | let history = window.utools.db.get("history"); 84 | if (history) { 85 | return history.data 86 | } 87 | return history; 88 | } 89 | 90 | 91 | const execCommand = function (itemData) { 92 | if (!itemData || !itemData.title) { 93 | return 94 | } 95 | require('child_process').exec(`osascript -e 'tell application "iTerm" 96 | activate 97 | try 98 | select current window 99 | tell current window 100 | create tab with default profile 101 | end tell 102 | tell current window 103 | tell current session to write text "ssh ${itemData.title}" 104 | end tell 105 | on error 106 | select current window 107 | tell current window 108 | tell current session to write text "ssh ${itemData.title}" 109 | end tell 110 | end try 111 | end tell'`, (error, stdout, stderr) => { 112 | if (error) return window.utools.showNotification(stderr) 113 | window.utools.outPlugin() 114 | }); 115 | addHistory(itemData) 116 | }; 117 | 118 | 119 | /** 120 | * 从关键字中提取host 121 | * 几种情况 122 | * ssh -p22 root@ip 123 | * ssh -p 22 root@ip 124 | * ssh ip1 125 | * @param searchWord 126 | */ 127 | function getHost(searchWord) { 128 | if (!searchWord) { 129 | return null; 130 | } 131 | if (searchWord.endWith('@')) { 132 | return null; 133 | } 134 | let split = searchWord.split(' '); 135 | if (split.length === 0) { 136 | return null 137 | } 138 | let endWord = split[split.length - 1]; 139 | if (endWord.indexOf("@") !== -1) { 140 | //ssh root@ip 141 | return endWord.split('@')[1] 142 | } 143 | if (endWord.indexOf('-') !== -1) { 144 | //如果最后一个是-p这样的参数 145 | return null; 146 | } 147 | return endWord 148 | 149 | } 150 | 151 | function handleHosts(searchWord, callbackSetList) { 152 | let hostsFilePath = "/etc/hosts"; 153 | let hostsData = (getHistory() || []) 154 | .filter(item => !searchWord || item.title.indexOf(searchWord) !== -1); 155 | if (!fs.existsSync(hostsFilePath)) { 156 | hostsData.unshift({ 157 | title: searchWord 158 | }, noHostsFile); 159 | callbackSetList(hostsData) 160 | return; 161 | } 162 | 163 | const fileData = fs.readFileSync(hostsFilePath, 'utf-8'); 164 | let dataLine = fileData.split(/[(\r\n)\r\n]+/); 165 | let host = getHost(searchWord); 166 | console.log(host) 167 | 168 | dataLine.forEach(line => { 169 | if (!line || line.trim().startsWith("#")) { 170 | return 171 | } 172 | let resetBlank = line.trim().resetBlank(); 173 | let split = resetBlank.split(' '); 174 | if (!split || split.length !== 2) { 175 | return 176 | } 177 | if (!host && !searchWord) { 178 | hostsData.push({ 179 | title: split[1].resetBlank(), 180 | description: split[0] 181 | }); 182 | return 183 | } 184 | if (host && resetBlank.indexOf(host) === -1) { 185 | return; 186 | } 187 | let end = searchWord.lastIndexOf(host); 188 | if (end === -1) { 189 | end = searchWord.length 190 | } 191 | let title = `${searchWord.substring(0, end)} ${split[1]}`; 192 | hostsData.push({ 193 | title: title.resetBlank().replace("@ ","@"), 194 | description: split[0] 195 | }); 196 | }); 197 | if (hostsData.length === 0) { 198 | if (searchWord) { 199 | callbackSetList([{ 200 | title: searchWord 201 | }]); 202 | } 203 | return 204 | } 205 | callbackSetList(hostsData) 206 | } 207 | 208 | 209 | window.exports = { 210 | "ssh_hosts": { 211 | mode: "list", 212 | args: { 213 | // 进入插件时调用(可选) 214 | enter: (action, callbackSetList) => { 215 | handleHosts(null, callbackSetList) 216 | }, 217 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 218 | search: (action, searchWord, callbackSetList) => { 219 | handleHosts((searchWord || '').resetBlank(), callbackSetList) 220 | }, 221 | // 用户选择列表中某个条目时被调用 222 | select: (action, itemData, callbackSetList) => { 223 | console.log(action) 224 | console.log(itemData) 225 | 226 | window.utools.hideMainWindow() 227 | execCommand(itemData) 228 | window.utools.outPlugin() 229 | }, 230 | placeholder: "搜索/输入 回车执行" 231 | } 232 | } 233 | } -------------------------------------------------------------------------------- /youdao-translate/preload.js: -------------------------------------------------------------------------------- 1 | const {clipboard} = require('electron') 2 | const https = require('https'); 3 | const querystring = require('querystring'); 4 | const SHA256 = require("./sha256"); 5 | const errorCode = require("./error_code").errorCode 6 | 7 | const noData = [{ 8 | title: '没有数据', 9 | icon: './logo.png' 10 | }] 11 | 12 | const noAppId = [{ 13 | title: '未设置app id,请阅读详情并按步骤设置', 14 | icon: './logo.png' 15 | }] 16 | 17 | 18 | const noAppSecret = [{ 19 | title: '未设置app secret,请阅读详情并按步骤设置', 20 | icon: './logo.png' 21 | }] 22 | 23 | const truncate = q => { 24 | var len = q.length; 25 | if (len <= 20) return q; 26 | return q.substring(0, 10) + len + q.substring(len - 10, len); 27 | }; 28 | 29 | const getFrom = searchWord => { 30 | const reg = /^[A-Za-z]+.*$/; 31 | if (reg.test(searchWord)) { 32 | return 'en' 33 | } 34 | return 'zh-CHS'; 35 | }; 36 | 37 | const getTo = from => { 38 | if (from === 'en') { 39 | return 'zh-CHS'; 40 | } 41 | return 'en'; 42 | }; 43 | 44 | 45 | const handleSearch = (searchWord, callbackSetList) => { 46 | const appId = getAppId(callbackSetList); 47 | if (appId === '') { 48 | return 49 | } 50 | const appSecret = getAppSecret(callbackSetList); 51 | if (appSecret === '') { 52 | return 53 | } 54 | const salt = (new Date()).getTime(); 55 | const curtime = Math.round(new Date().getTime() / 1000); 56 | const from = getFrom(searchWord); 57 | const to = getTo(from); 58 | // var to = 'en'; 59 | const str1 = appId + truncate(searchWord) + salt + curtime + appSecret; 60 | 61 | const sign = SHA256(str1); 62 | const param = { 63 | q: searchWord, 64 | appKey: appId, 65 | salt: salt, 66 | from: from, 67 | to: to, 68 | sign: sign, 69 | signType: "v3", 70 | curtime: curtime 71 | }; 72 | 73 | https.get({ 74 | hostname: 'openapi.youdao.com', 75 | path: '/api?' + querystring.stringify(param), 76 | timeout: 30000 77 | }, (res) => { 78 | res.on('data', function (data) { 79 | let jsonData = JSON.parse(data); 80 | if (jsonData.errorCode !== '0') { 81 | callbackSetList([{ 82 | title: errorCode.get(jsonData.errorCode), 83 | description: '查询错误', 84 | icon: './logo.png' 85 | }]) 86 | return 87 | } 88 | let items = []; 89 | if (jsonData.translation) { 90 | jsonData.translation.forEach(item => { 91 | items.push({ 92 | title: item, 93 | description: searchWord, 94 | icon: './logo.png' 95 | }); 96 | }) 97 | } 98 | let exist = items.map(item => item.title); 99 | if (jsonData.web) { 100 | jsonData.web.forEach(item => { 101 | let desc = item.key; 102 | item.value.forEach(v => { 103 | if (exist.includes(v)) { 104 | return 105 | } 106 | items.push({ 107 | title: v, 108 | description: desc, 109 | icon: './logo.png' 110 | }); 111 | }) 112 | }); 113 | } 114 | if (items.length === 0) { 115 | callbackSetList(noData) 116 | return 117 | } 118 | callbackSetList(items); 119 | }); 120 | } 121 | ) 122 | }; 123 | 124 | const handleResult = function (itemData) { 125 | if (itemData.title) { 126 | clipboard.writeText(itemData.title, 'selection'); 127 | } 128 | }; 129 | 130 | 131 | const saveOrUpdateDb = function (key, data) { 132 | if (!data) { 133 | return 134 | } 135 | let keyData = window.utools.db.get(key); 136 | if (!keyData) { 137 | window.utools.db.put({ 138 | _id: key, 139 | data: data 140 | }) 141 | return 142 | } 143 | utools.db.put({ 144 | _id: key, 145 | data: data, 146 | _rev: keyData._rev 147 | }) 148 | }; 149 | 150 | const getAppId = function (callbackSetList) { 151 | let appId = window.utools.db.get("app_id"); 152 | if (!appId) { 153 | callbackSetList(noAppId) 154 | return '' 155 | } 156 | return appId.data 157 | }; 158 | 159 | const getAppSecret = function (callbackSetList) { 160 | let appSecret = window.utools.db.get("app_secret"); 161 | if (!appSecret) { 162 | callbackSetList(noAppSecret) 163 | return '' 164 | } 165 | return appSecret.data 166 | }; 167 | 168 | const addHistory = item => { 169 | if (!item) { 170 | return 171 | } 172 | let title = item.title; 173 | let history = getHistory()||[]; 174 | let index = -1; 175 | for (let i = 0; i < history.length; i++) { 176 | if (history[i].title === title) { 177 | index = i; 178 | } 179 | } 180 | if (index !== -1) { 181 | history.splice(index, 1); 182 | } 183 | history.unshift(item); 184 | if (history.length > 20) { 185 | history = history.slice(0, 20); 186 | } 187 | saveOrUpdateDb('history', history); 188 | }; 189 | 190 | const getHistory = function () { 191 | let history = window.utools.db.get("history"); 192 | if (history) { 193 | return history.data 194 | } 195 | return history; 196 | } 197 | 198 | window.exports = { 199 | "youdao-translate": { 200 | mode: "list", 201 | args: { 202 | // 进入插件时调用(可选) 203 | enter: (action, callbackSetList) => { 204 | if (action.type === 'over' && action.payload) { 205 | // 直接调用setSubInputValue不生效,特殊处理 206 | setTimeout(function () { 207 | window.utools.setSubInputValue(action.payload); 208 | }, 50); 209 | } else { 210 | let history = getHistory(); 211 | if (history) { 212 | callbackSetList(history) 213 | } 214 | } 215 | }, 216 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 217 | search: (action, searchWord, callbackSetList) => { 218 | if (searchWord) { 219 | handleSearch(searchWord, callbackSetList); 220 | } 221 | }, 222 | // 用户选择列表中某个条目时被调用 223 | select: (action, itemData, callbackSetList) => { 224 | window.utools.hideMainWindow() 225 | handleResult(itemData) 226 | addHistory(itemData) 227 | window.utools.outPlugin() 228 | }, 229 | placeholder: "搜索" 230 | } 231 | }, 232 | "youdao-app-id": { 233 | mode: "list", 234 | args: { 235 | enter: (action, callbackSetList) => { 236 | //显示当前app id 237 | let id = getAppId(callbackSetList); 238 | if (id !== '') { 239 | callbackSetList([{ 240 | title: id, 241 | description: '已设置', 242 | icon: './logo.png' 243 | }]); 244 | } 245 | }, 246 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 247 | search: (action, searchWord, callbackSetList) => { 248 | saveOrUpdateDb('app_id', searchWord); 249 | }, 250 | // 用户选择列表中某个条目时被调用 251 | select: (action, itemData, callbackSetList) => { 252 | window.utools.hideMainWindow() 253 | handleResult(itemData) 254 | window.utools.outPlugin() 255 | }, 256 | placeholder: "输入appId自动保存" 257 | } 258 | }, 259 | "youdao-app-secret": { 260 | mode: "list", 261 | args: { 262 | enter: (action, callbackSetList) => { 263 | //显示当前app id 264 | let secret = getAppSecret(callbackSetList); 265 | if (secret !== '') { 266 | callbackSetList([{ 267 | title: secret, 268 | description: '已设置', 269 | icon: './logo.png' 270 | }]); 271 | } 272 | }, 273 | // 子输入框内容变化时被调用 可选 (未设置则无搜索) 274 | search: (action, searchWord, callbackSetList) => { 275 | saveOrUpdateDb("app_secret", searchWord); 276 | }, 277 | // 用户选择列表中某个条目时被调用 278 | select: (action, itemData, callbackSetList) => { 279 | window.utools.hideMainWindow() 280 | handleResult(itemData) 281 | window.utools.outPlugin() 282 | }, 283 | placeholder: "输入secret自动保存" 284 | } 285 | } 286 | } -------------------------------------------------------------------------------- /youdao-translate/sha256.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [js-sha256]{@link https://github.com/emn178/js-sha256} 3 | * 4 | * @version 0.9.0 5 | * @author Chen, Yi-Cyuan [emn178@gmail.com] 6 | * @copyright Chen, Yi-Cyuan 2014-2017 7 | * @license MIT 8 | */ 9 | /*jslint bitwise: true */ 10 | (function () { 11 | 'use strict'; 12 | 13 | var ERROR = 'input is invalid type'; 14 | var WINDOW = typeof window === 'object'; 15 | var root = WINDOW ? window : {}; 16 | if (root.JS_SHA256_NO_WINDOW) { 17 | WINDOW = false; 18 | } 19 | var WEB_WORKER = !WINDOW && typeof self === 'object'; 20 | var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; 21 | if (NODE_JS) { 22 | root = global; 23 | } else if (WEB_WORKER) { 24 | root = self; 25 | } 26 | var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports; 27 | var AMD = typeof define === 'function' && define.amd; 28 | var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; 29 | var HEX_CHARS = '0123456789abcdef'.split(''); 30 | var EXTRA = [-2147483648, 8388608, 32768, 128]; 31 | var SHIFT = [24, 16, 8, 0]; 32 | var K = [ 33 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 34 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 35 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 36 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 37 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 38 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 39 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 40 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 41 | ]; 42 | var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer']; 43 | 44 | var blocks = []; 45 | 46 | if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) { 47 | Array.isArray = function (obj) { 48 | return Object.prototype.toString.call(obj) === '[object Array]'; 49 | }; 50 | } 51 | 52 | if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { 53 | ArrayBuffer.isView = function (obj) { 54 | return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; 55 | }; 56 | } 57 | 58 | var createOutputMethod = function (outputType, is224) { 59 | return function (message) { 60 | return new Sha256(is224, true).update(message)[outputType](); 61 | }; 62 | }; 63 | 64 | var createMethod = function (is224) { 65 | var method = createOutputMethod('hex', is224); 66 | if (NODE_JS) { 67 | method = nodeWrap(method, is224); 68 | } 69 | method.create = function () { 70 | return new Sha256(is224); 71 | }; 72 | method.update = function (message) { 73 | return method.create().update(message); 74 | }; 75 | for (var i = 0; i < OUTPUT_TYPES.length; ++i) { 76 | var type = OUTPUT_TYPES[i]; 77 | method[type] = createOutputMethod(type, is224); 78 | } 79 | return method; 80 | }; 81 | 82 | var nodeWrap = function (method, is224) { 83 | var crypto = eval("require('crypto')"); 84 | var Buffer = eval("require('buffer').Buffer"); 85 | var algorithm = is224 ? 'sha224' : 'sha256'; 86 | var nodeMethod = function (message) { 87 | if (typeof message === 'string') { 88 | return crypto.createHash(algorithm).update(message, 'utf8').digest('hex'); 89 | } else { 90 | if (message === null || message === undefined) { 91 | throw new Error(ERROR); 92 | } else if (message.constructor === ArrayBuffer) { 93 | message = new Uint8Array(message); 94 | } 95 | } 96 | if (Array.isArray(message) || ArrayBuffer.isView(message) || 97 | message.constructor === Buffer) { 98 | return crypto.createHash(algorithm).update(new Buffer(message)).digest('hex'); 99 | } else { 100 | return method(message); 101 | } 102 | }; 103 | return nodeMethod; 104 | }; 105 | 106 | var createHmacOutputMethod = function (outputType, is224) { 107 | return function (key, message) { 108 | return new HmacSha256(key, is224, true).update(message)[outputType](); 109 | }; 110 | }; 111 | 112 | var createHmacMethod = function (is224) { 113 | var method = createHmacOutputMethod('hex', is224); 114 | method.create = function (key) { 115 | return new HmacSha256(key, is224); 116 | }; 117 | method.update = function (key, message) { 118 | return method.create(key).update(message); 119 | }; 120 | for (var i = 0; i < OUTPUT_TYPES.length; ++i) { 121 | var type = OUTPUT_TYPES[i]; 122 | method[type] = createHmacOutputMethod(type, is224); 123 | } 124 | return method; 125 | }; 126 | 127 | function Sha256(is224, sharedMemory) { 128 | if (sharedMemory) { 129 | blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = 130 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 131 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 132 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 133 | this.blocks = blocks; 134 | } else { 135 | this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 136 | } 137 | 138 | if (is224) { 139 | this.h0 = 0xc1059ed8; 140 | this.h1 = 0x367cd507; 141 | this.h2 = 0x3070dd17; 142 | this.h3 = 0xf70e5939; 143 | this.h4 = 0xffc00b31; 144 | this.h5 = 0x68581511; 145 | this.h6 = 0x64f98fa7; 146 | this.h7 = 0xbefa4fa4; 147 | } else { // 256 148 | this.h0 = 0x6a09e667; 149 | this.h1 = 0xbb67ae85; 150 | this.h2 = 0x3c6ef372; 151 | this.h3 = 0xa54ff53a; 152 | this.h4 = 0x510e527f; 153 | this.h5 = 0x9b05688c; 154 | this.h6 = 0x1f83d9ab; 155 | this.h7 = 0x5be0cd19; 156 | } 157 | 158 | this.block = this.start = this.bytes = this.hBytes = 0; 159 | this.finalized = this.hashed = false; 160 | this.first = true; 161 | this.is224 = is224; 162 | } 163 | 164 | Sha256.prototype.update = function (message) { 165 | if (this.finalized) { 166 | return; 167 | } 168 | var notString, type = typeof message; 169 | if (type !== 'string') { 170 | if (type === 'object') { 171 | if (message === null) { 172 | throw new Error(ERROR); 173 | } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) { 174 | message = new Uint8Array(message); 175 | } else if (!Array.isArray(message)) { 176 | if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { 177 | throw new Error(ERROR); 178 | } 179 | } 180 | } else { 181 | throw new Error(ERROR); 182 | } 183 | notString = true; 184 | } 185 | var code, index = 0, i, length = message.length, blocks = this.blocks; 186 | 187 | while (index < length) { 188 | if (this.hashed) { 189 | this.hashed = false; 190 | blocks[0] = this.block; 191 | blocks[16] = blocks[1] = blocks[2] = blocks[3] = 192 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 193 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 194 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 195 | } 196 | 197 | if (notString) { 198 | for (i = this.start; index < length && i < 64; ++index) { 199 | blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; 200 | } 201 | } else { 202 | for (i = this.start; index < length && i < 64; ++index) { 203 | code = message.charCodeAt(index); 204 | if (code < 0x80) { 205 | blocks[i >> 2] |= code << SHIFT[i++ & 3]; 206 | } else if (code < 0x800) { 207 | blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; 208 | blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 209 | } else if (code < 0xd800 || code >= 0xe000) { 210 | blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; 211 | blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; 212 | blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 213 | } else { 214 | code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); 215 | blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; 216 | blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; 217 | blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; 218 | blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 219 | } 220 | } 221 | } 222 | 223 | this.lastByteIndex = i; 224 | this.bytes += i - this.start; 225 | if (i >= 64) { 226 | this.block = blocks[16]; 227 | this.start = i - 64; 228 | this.hash(); 229 | this.hashed = true; 230 | } else { 231 | this.start = i; 232 | } 233 | } 234 | if (this.bytes > 4294967295) { 235 | this.hBytes += this.bytes / 4294967296 << 0; 236 | this.bytes = this.bytes % 4294967296; 237 | } 238 | return this; 239 | }; 240 | 241 | Sha256.prototype.finalize = function () { 242 | if (this.finalized) { 243 | return; 244 | } 245 | this.finalized = true; 246 | var blocks = this.blocks, i = this.lastByteIndex; 247 | blocks[16] = this.block; 248 | blocks[i >> 2] |= EXTRA[i & 3]; 249 | this.block = blocks[16]; 250 | if (i >= 56) { 251 | if (!this.hashed) { 252 | this.hash(); 253 | } 254 | blocks[0] = this.block; 255 | blocks[16] = blocks[1] = blocks[2] = blocks[3] = 256 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 257 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 258 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 259 | } 260 | blocks[14] = this.hBytes << 3 | this.bytes >>> 29; 261 | blocks[15] = this.bytes << 3; 262 | this.hash(); 263 | }; 264 | 265 | Sha256.prototype.hash = function () { 266 | var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6, 267 | h = this.h7, blocks = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc; 268 | 269 | for (j = 16; j < 64; ++j) { 270 | // rightrotate 271 | t1 = blocks[j - 15]; 272 | s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3); 273 | t1 = blocks[j - 2]; 274 | s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10); 275 | blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0; 276 | } 277 | 278 | bc = b & c; 279 | for (j = 0; j < 64; j += 4) { 280 | if (this.first) { 281 | if (this.is224) { 282 | ab = 300032; 283 | t1 = blocks[0] - 1413257819; 284 | h = t1 - 150054599 << 0; 285 | d = t1 + 24177077 << 0; 286 | } else { 287 | ab = 704751109; 288 | t1 = blocks[0] - 210244248; 289 | h = t1 - 1521486534 << 0; 290 | d = t1 + 143694565 << 0; 291 | } 292 | this.first = false; 293 | } else { 294 | s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10)); 295 | s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7)); 296 | ab = a & b; 297 | maj = ab ^ (a & c) ^ bc; 298 | ch = (e & f) ^ (~e & g); 299 | t1 = h + s1 + ch + K[j] + blocks[j]; 300 | t2 = s0 + maj; 301 | h = d + t1 << 0; 302 | d = t1 + t2 << 0; 303 | } 304 | s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10)); 305 | s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7)); 306 | da = d & a; 307 | maj = da ^ (d & b) ^ ab; 308 | ch = (h & e) ^ (~h & f); 309 | t1 = g + s1 + ch + K[j + 1] + blocks[j + 1]; 310 | t2 = s0 + maj; 311 | g = c + t1 << 0; 312 | c = t1 + t2 << 0; 313 | s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10)); 314 | s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7)); 315 | cd = c & d; 316 | maj = cd ^ (c & a) ^ da; 317 | ch = (g & h) ^ (~g & e); 318 | t1 = f + s1 + ch + K[j + 2] + blocks[j + 2]; 319 | t2 = s0 + maj; 320 | f = b + t1 << 0; 321 | b = t1 + t2 << 0; 322 | s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10)); 323 | s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7)); 324 | bc = b & c; 325 | maj = bc ^ (b & d) ^ cd; 326 | ch = (f & g) ^ (~f & h); 327 | t1 = e + s1 + ch + K[j + 3] + blocks[j + 3]; 328 | t2 = s0 + maj; 329 | e = a + t1 << 0; 330 | a = t1 + t2 << 0; 331 | } 332 | 333 | this.h0 = this.h0 + a << 0; 334 | this.h1 = this.h1 + b << 0; 335 | this.h2 = this.h2 + c << 0; 336 | this.h3 = this.h3 + d << 0; 337 | this.h4 = this.h4 + e << 0; 338 | this.h5 = this.h5 + f << 0; 339 | this.h6 = this.h6 + g << 0; 340 | this.h7 = this.h7 + h << 0; 341 | }; 342 | 343 | Sha256.prototype.hex = function () { 344 | this.finalize(); 345 | 346 | var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, 347 | h6 = this.h6, h7 = this.h7; 348 | 349 | var hex = HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + 350 | HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + 351 | HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + 352 | HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + 353 | HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + 354 | HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + 355 | HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + 356 | HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + 357 | HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + 358 | HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + 359 | HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + 360 | HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + 361 | HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + 362 | HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + 363 | HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + 364 | HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + 365 | HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + 366 | HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + 367 | HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + 368 | HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] + 369 | HEX_CHARS[(h5 >> 28) & 0x0F] + HEX_CHARS[(h5 >> 24) & 0x0F] + 370 | HEX_CHARS[(h5 >> 20) & 0x0F] + HEX_CHARS[(h5 >> 16) & 0x0F] + 371 | HEX_CHARS[(h5 >> 12) & 0x0F] + HEX_CHARS[(h5 >> 8) & 0x0F] + 372 | HEX_CHARS[(h5 >> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] + 373 | HEX_CHARS[(h6 >> 28) & 0x0F] + HEX_CHARS[(h6 >> 24) & 0x0F] + 374 | HEX_CHARS[(h6 >> 20) & 0x0F] + HEX_CHARS[(h6 >> 16) & 0x0F] + 375 | HEX_CHARS[(h6 >> 12) & 0x0F] + HEX_CHARS[(h6 >> 8) & 0x0F] + 376 | HEX_CHARS[(h6 >> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F]; 377 | if (!this.is224) { 378 | hex += HEX_CHARS[(h7 >> 28) & 0x0F] + HEX_CHARS[(h7 >> 24) & 0x0F] + 379 | HEX_CHARS[(h7 >> 20) & 0x0F] + HEX_CHARS[(h7 >> 16) & 0x0F] + 380 | HEX_CHARS[(h7 >> 12) & 0x0F] + HEX_CHARS[(h7 >> 8) & 0x0F] + 381 | HEX_CHARS[(h7 >> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F]; 382 | } 383 | return hex; 384 | }; 385 | 386 | Sha256.prototype.toString = Sha256.prototype.hex; 387 | 388 | Sha256.prototype.digest = function () { 389 | this.finalize(); 390 | 391 | var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, 392 | h6 = this.h6, h7 = this.h7; 393 | 394 | var arr = [ 395 | (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF, 396 | (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF, 397 | (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF, 398 | (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF, 399 | (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF, 400 | (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, h5 & 0xFF, 401 | (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, h6 & 0xFF 402 | ]; 403 | if (!this.is224) { 404 | arr.push((h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, h7 & 0xFF); 405 | } 406 | return arr; 407 | }; 408 | 409 | Sha256.prototype.array = Sha256.prototype.digest; 410 | 411 | Sha256.prototype.arrayBuffer = function () { 412 | this.finalize(); 413 | 414 | var buffer = new ArrayBuffer(this.is224 ? 28 : 32); 415 | var dataView = new DataView(buffer); 416 | dataView.setUint32(0, this.h0); 417 | dataView.setUint32(4, this.h1); 418 | dataView.setUint32(8, this.h2); 419 | dataView.setUint32(12, this.h3); 420 | dataView.setUint32(16, this.h4); 421 | dataView.setUint32(20, this.h5); 422 | dataView.setUint32(24, this.h6); 423 | if (!this.is224) { 424 | dataView.setUint32(28, this.h7); 425 | } 426 | return buffer; 427 | }; 428 | 429 | function HmacSha256(key, is224, sharedMemory) { 430 | var i, type = typeof key; 431 | if (type === 'string') { 432 | var bytes = [], length = key.length, index = 0, code; 433 | for (i = 0; i < length; ++i) { 434 | code = key.charCodeAt(i); 435 | if (code < 0x80) { 436 | bytes[index++] = code; 437 | } else if (code < 0x800) { 438 | bytes[index++] = (0xc0 | (code >> 6)); 439 | bytes[index++] = (0x80 | (code & 0x3f)); 440 | } else if (code < 0xd800 || code >= 0xe000) { 441 | bytes[index++] = (0xe0 | (code >> 12)); 442 | bytes[index++] = (0x80 | ((code >> 6) & 0x3f)); 443 | bytes[index++] = (0x80 | (code & 0x3f)); 444 | } else { 445 | code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff)); 446 | bytes[index++] = (0xf0 | (code >> 18)); 447 | bytes[index++] = (0x80 | ((code >> 12) & 0x3f)); 448 | bytes[index++] = (0x80 | ((code >> 6) & 0x3f)); 449 | bytes[index++] = (0x80 | (code & 0x3f)); 450 | } 451 | } 452 | key = bytes; 453 | } else { 454 | if (type === 'object') { 455 | if (key === null) { 456 | throw new Error(ERROR); 457 | } else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) { 458 | key = new Uint8Array(key); 459 | } else if (!Array.isArray(key)) { 460 | if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) { 461 | throw new Error(ERROR); 462 | } 463 | } 464 | } else { 465 | throw new Error(ERROR); 466 | } 467 | } 468 | 469 | if (key.length > 64) { 470 | key = (new Sha256(is224, true)).update(key).array(); 471 | } 472 | 473 | var oKeyPad = [], iKeyPad = []; 474 | for (i = 0; i < 64; ++i) { 475 | var b = key[i] || 0; 476 | oKeyPad[i] = 0x5c ^ b; 477 | iKeyPad[i] = 0x36 ^ b; 478 | } 479 | 480 | Sha256.call(this, is224, sharedMemory); 481 | 482 | this.update(iKeyPad); 483 | this.oKeyPad = oKeyPad; 484 | this.inner = true; 485 | this.sharedMemory = sharedMemory; 486 | } 487 | HmacSha256.prototype = new Sha256(); 488 | 489 | HmacSha256.prototype.finalize = function () { 490 | Sha256.prototype.finalize.call(this); 491 | if (this.inner) { 492 | this.inner = false; 493 | var innerHash = this.array(); 494 | Sha256.call(this, this.is224, this.sharedMemory); 495 | this.update(this.oKeyPad); 496 | this.update(innerHash); 497 | Sha256.prototype.finalize.call(this); 498 | } 499 | }; 500 | 501 | var exports = createMethod(); 502 | exports.sha256 = exports; 503 | exports.sha224 = createMethod(true); 504 | exports.sha256.hmac = createHmacMethod(); 505 | exports.sha224.hmac = createHmacMethod(true); 506 | 507 | if (COMMON_JS) { 508 | module.exports = exports; 509 | } else { 510 | root.sha256 = exports.sha256; 511 | root.sha224 = exports.sha224; 512 | if (AMD) { 513 | define(function () { 514 | return exports; 515 | }); 516 | } 517 | } 518 | })(); --------------------------------------------------------------------------------