This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
appcat
/
dtalk-app
Archived
1
0
Fork 0

Compare commits

...

10 Commits

Author SHA1 Message Date
yutent c38ae42cc8 remove debug 2022-04-26 14:18:13 +08:00
yutent b160e1a7da merged 2022-04-26 14:15:12 +08:00
yutent 6ef954b96c Merge branch 'master' of github.com:yutent/dtalk-app 2022-04-26 14:14:34 +08:00
yutent ff8b6588d2 增加未读消息检测 2022-04-26 14:14:13 +08:00
宇天 94081982c3 Update Readme.md 2022-04-25 02:38:17 +08:00
yutent 50e150199e 3.8.12 2022-04-24 15:34:38 +08:00
宇天 a89b162eed update download page 2019-08-13 16:21:44 +08:00
宇天 d05a8cad27 注释DEVTOOLS 2019-08-13 15:51:12 +08:00
宇天 8842df25dc 优化app内链接跳转 2019-08-13 15:50:05 +08:00
宇天 e230fa13b3 .. 2019-08-09 16:15:51 +08:00
7 changed files with 194 additions and 53 deletions

View File

@ -1,10 +1,10 @@
# 钉钉App - Linux版 # 钉钉App - Linux版
> `非官方版` > `非官方版`
> 最新的3.8.7改用electron封装。 > 3.8.7改用electron封装。
>> 因为最近钉钉取消了账号登录, 所以移除了之前记住账号的 注入脚本。 >> 因为最近钉钉取消了账号登录, 所以移除了之前记住账号的 注入脚本。
>> 注入改为缓存登录token, 然后在下次启动时,把token放出来, 以达到自动登录的效果。(token的有效期为15天, 这是钉钉自己设置的, 项目没有对它进行任何修改) >> 注入改为缓存登录token, 然后在下次启动时,把token放出来, 以达到自动登录的效果。(token的有效期为15天, 这是钉钉自己设置的, 项目没有对它进行任何修改)
>> **`注意: 该注入不一定能用。`**
该修改版并不对钉钉现有功能进行任何的修改,也不收集任何信息。 该修改版并不对钉钉现有功能进行任何的修改,也不收集任何信息。
代码量很少, 而且完全开源, 请放心使用。 代码量很少, 而且完全开源, 请放心使用。
@ -14,8 +14,23 @@
![preview](./preview.png) ![preview](./preview.png)
## 更新日志
- 2022.04.26
1. 版本号改为`年.月.日`格式
2. 检测未读消息, 如有, 托盘图标显示红点。
- 2022.04.24
1. electron升级为18.0
2. 修复自动登录功能
3. 禁用`nodejs`, 注入更为安全
4. 包名修改为`top.yutent.dtalk`, 之前有安装过旧版的, 请先卸载
5. 不再打包`AppImage`版本, 其他非`debian`系发行版的, 请自行编译
## 打包好的安装包 ## 打包好的安装包
请进入`release`页面下载.
下载地址请转到`release`页面
## 自行打包 ## 自行打包
@ -32,4 +47,4 @@ npm run pack
**注:** 本程序只是为了方便个人使用而进行的封装, 现在应网友要求上传到github供学习参考之用, 请勿用于非法途径, 由此产生的一切后果与本人无关。 **注:** 本程序只是为了方便个人使用而进行的封装, 现在应网友要求上传到github供学习参考之用, 请勿用于非法途径, 由此产生的一切后果与本人无关。

View File

@ -1,6 +1,6 @@
{ {
"name": "dtalk", "name": "dtalk",
"version": "3.8.7", "version": "22.4.26",
"description": "钉钉-Linux版", "description": "钉钉-Linux版",
"main": "src/main.js", "main": "src/main.js",
"scripts": { "scripts": {
@ -9,31 +9,33 @@
}, },
"author": { "author": {
"name": "yutent", "name": "yutent",
"email": "yutent@doui.cc" "email": "yutent.io@gmail.com"
}, },
"devDependencies": { "devDependencies": {
"electron": "^6.0.0", "electron": "^18.0.0",
"electron-builder": "^21.2.0" "electron-builder": "^23.0.0"
}, },
"build": { "build": {
"appId": "cc.doui.dtalk", "appId": "top.yutent.dtalk",
"productName": "DingDing", "productName": "钉钉(DingTalk)",
"electronDownload": {
"version": "18.1.0",
"mirror": "https://npm.taobao.org/mirrors/electron/"
},
"copyright": "Copyright © 2019 ${author}", "copyright": "Copyright © 2019 ${author}",
"directories": { "directories": {
"buildResources": "icons", "buildResources": "icons",
"output": "build" "output": "build"
}, },
"files": ["src/**/*"], "files": [
"src/**/*"
],
"linux": { "linux": {
"category": "Network;Chat", "category": "Network;Chat",
"target": [ "target": [
{ {
"target": "deb", "target": "deb",
"arch": "x64" "arch": "x64"
},
{
"target": "AppImage",
"arch": "x64"
} }
], ],
"icon": "./icons/" "icon": "./icons/"

BIN
src/images/tray_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,13 +1,15 @@
/* app */ /* app */
const { app, session, Menu } = require('electron') const { app, session, Menu, ipcMain } = require('electron')
const path = require('path') const { join } = require('path')
const fs = require('fs')
const log = console.log
const createTray = require('./tools/tray') const createTray = require('./tools/tray')
const { createMainWindow } = require('./tools/windows') const { createMainWindow } = require('./tools/windows')
const ROOT = __dirname const ROOT = __dirname
const APP_DIR = join(app.getPath('appData'), './dtalk')
const sessionFile = join(APP_DIR, './login_session.json')
const cookieFile = join(APP_DIR, './login_cookie.json')
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
@ -22,10 +24,61 @@ Menu.setApplicationMenu(null)
app.once('ready', () => { app.once('ready', () => {
// 修改app的UA // 修改app的UA
session.defaultSession.setUserAgent( session.defaultSession.setUserAgent(
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36'
) )
let win = createMainWindow(path.join(ROOT, './images/app.png')) let win = createMainWindow(join(ROOT, './images/app.png'))
createTray(win) app.toggleTray = createTray(win)
})
ipcMain.on('app', (ev, conn) => {
switch (conn.type) {
case 'saveToken':
fs.writeFile(sessionFile, conn.data, function (err) {})
ev.returnValue = true
break
case 'readToken':
{
let cache = ''
try {
cache = fs.readFileSync(sessionFile).toString()
} catch (err) {}
ev.returnValue = cache
}
break
case 'restoreCookie':
{
try {
let cache = fs.readFileSync(cookieFile).toString()
cache = JSON.parse(cache)
for (let it of cache) {
it.url = 'https://im.dingtalk.com'
session.defaultSession.cookies.set(it)
}
} catch (err) {}
ev.returnValue = true
}
break
case 'saveCookie':
{
let cookie = session.defaultSession.cookies.get({})
cookie.then(r => {
fs.writeFile(cookieFile, JSON.stringify(r), function (err) {})
})
ev.returnValue = true
}
break
case 'toggleTray':
{
app.toggleTray(conn.data)
ev.returnValue = true
}
break
}
}) })

32
src/tools/inject.js Normal file
View File

@ -0,0 +1,32 @@
const { ipcRenderer, shell, contextBridge } = require('electron')
contextBridge.exposeInMainWorld('electron', {
open(url) {
shell.openExternal(url)
},
saveToken(id, token) {
token = JSON.parse(token)
// token.isAutoLogin = true
token = JSON.stringify(token)
ipcRenderer.sendSync('app', {
data: JSON.stringify({ id, token }),
type: 'saveToken'
})
},
readToken() {
return ipcRenderer.sendSync('app', { type: 'readToken' })
},
restoreCookie() {
return ipcRenderer.sendSync('app', { type: 'restoreCookie' })
},
saveCookie() {
return ipcRenderer.sendSync('app', { type: 'saveCookie' })
},
toggleTray(unread) {
return ipcRenderer.sendSync('app', { type: 'toggleTray', data: unread })
}
})

View File

@ -1,17 +1,18 @@
/** /**
* 托盘 * 托盘
* @author yutent<yutent@doui.cc> * @author yutent<yutent.io@gmail.com>
* @date 2019/01/21 20:42:07 * @date 2019/01/21 20:42:07
*/ */
'use strict'
const { app, Tray, Menu } = require('electron') const { app, Tray, Menu } = require('electron')
const path = require('path') const path = require('path')
const ROOT = __dirname const ROOT = __dirname
module.exports = function(win) { const TRAY_ICO = path.join(ROOT, '../images/tray.png')
app.__TRAY__ = new Tray(path.join(ROOT, '../images/tray.png')) const TRAY_ICO_A = path.join(ROOT, '../images/tray_a.png')
module.exports = function (win) {
let dTray = new Tray(TRAY_ICO)
let menuList = Menu.buildFromTemplate([ let menuList = Menu.buildFromTemplate([
{ {
label: '显示主窗口', label: '显示主窗口',
@ -27,9 +28,25 @@ module.exports = function(win) {
} }
} }
]) ])
app.__TRAY__.on('click', _ => { let unreadCache = false
dTray.on('click', _ => {
win.show() win.show()
}) })
app.__TRAY__.setContextMenu(menuList) dTray.setContextMenu(menuList)
return function (unread) {
// 缓存状态, 避免频繁修改tray图标
if (unreadCache === unread) {
return
}
unreadCache = unread
if (unread) {
dTray.setImage(TRAY_ICO_A)
} else {
dTray.setImage(TRAY_ICO)
}
}
} }

View File

@ -1,17 +1,16 @@
/** /**
* 各种窗口创建 * 各种窗口创建
* @author yutent<yutent@doui.cc> * @author yutent<yutent.io@gmail.com>
* @date 2019/01/26 18:28:22 * @date 2019/01/26 18:28:22
*/ */
'use strict' const { join } = require('path')
const { BrowserWindow } = require('electron') const { BrowserWindow } = require('electron')
/** /**
* 应用主窗口 * 应用主窗口
*/ */
exports.createMainWindow = function(icon) { exports.createMainWindow = function (icon) {
// 创建浏览器窗口 // 创建浏览器窗口
let win = new BrowserWindow({ let win = new BrowserWindow({
title: '钉钉-electron版', title: '钉钉-electron版',
@ -23,14 +22,12 @@ exports.createMainWindow = function(icon) {
webPreferences: { webPreferences: {
webSecurity: false, webSecurity: false,
experimentalFeatures: true, experimentalFeatures: true,
nodeIntegration: true // nodeIntegration: true,
preload: join(__dirname, './inject.js')
}, },
show: false show: false
}) })
// 然后加载应用的 index.html。
// win.loadURL('app://local/index.html')
win.loadURL('https://im.dingtalk.com') win.loadURL('https://im.dingtalk.com')
win.on('ready-to-show', _ => { win.on('ready-to-show', _ => {
@ -42,31 +39,53 @@ exports.createMainWindow = function(icon) {
win.webContents.on('dom-ready', ev => { win.webContents.on('dom-ready', ev => {
win.webContents.executeJavaScript( win.webContents.executeJavaScript(
` `
const shell = require('electron').shell;
// assuming $ is jQuery
$(document).on('click', 'a[href^="http"]', function(event) { $(document).on('click', 'a[href^="http"]', function(event) {
event.preventDefault(); if(!this.hasAttribute('nwdirectory')){
shell.openExternal(this.href); event.preventDefault();
electron.open(this.href)
}
}); });
localStorage.setItem("isBeepOpen", "true"); localStorage.setItem("isBeepOpen", "true");
localStorage.setItem("notification", "true"); localStorage.setItem("notification", "true");
localStorage.setItem("newUserState", "secTip"); localStorage.setItem("newUserState", "secTip");
localStorage.setItem("latest_lang_info", "zh_CN"); localStorage.setItem("latest_lang_info", "zh_CN");
localStorage.setItem("login_method", "autoLogin");
if(localStorage.getItem('fuck2')){
let cache = electron.readToken()
sessionStorage.setItem('wk_device_id', localStorage.getItem('fuck1'))
sessionStorage.setItem('wk_token', localStorage.getItem('fuck2')) if(cache){
cache = JSON.parse(cache)
sessionStorage.setItem('wk_device_id', cache.id)
sessionStorage.setItem('wk_token', cache.token)
electron.restoreCookie()
// 第一次进来刷新一下页面, 才会自动登录
if(!sessionStorage.getItem('first_in')){
sessionStorage.setItem('first_in', 1)
setTimeout(function(){
location.reload()
}, 2000)
}
function checkUnReadMsg() {
window.__timer = setTimeout(function() {
var $box = document.body.querySelector('.conv-lists-box')
var $unread = $box.querySelectorAll('.unread-num')
electro($unread.length > 0)
clearTimeout(window.__timer)
checkUnReadMsg()
}, 1500)
}
checkUnReadMsg()
} }
if(!sessionStorage.getItem('first_in')){
sessionStorage.setItem('first_in', 1)
location.reload()
}
`, `,
true true
@ -79,9 +98,12 @@ exports.createMainWindow = function(icon) {
` `
if(sessionStorage.getItem('wk_token')){ if(sessionStorage.getItem('wk_token')){
localStorage.setItem('fuck1', sessionStorage.getItem('wk_device_id')) electron.saveCookie()
localStorage.setItem('fuck2', sessionStorage.getItem('wk_token')) electron.saveToken(
sessionStorage.getItem('wk_device_id'),
sessionStorage.getItem('wk_token')
)
} }
`, `,