mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-05-12 02:19:55 +08:00
Merge branch 'feat/login-with-edit-this-cookie' into feature/ui
This commit is contained in:
@@ -1,3 +1,2 @@
|
||||
{
|
||||
"cookies": []
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -8,12 +8,16 @@ import os from 'node:os'
|
||||
import { get__dirname } from '@geekgeekrun/utils/legacy-path.mjs';
|
||||
import path from 'node:path';
|
||||
import JSON5 from 'json5'
|
||||
import { EventEmitter } from 'node:events'
|
||||
import { setDomainLocalStorage } from '@geekgeekrun/utils/puppeteer/local-storage.mjs'
|
||||
|
||||
import { readConfigFile, ensureConfigFileExist } from './runtime-file-utils.mjs'
|
||||
import { readConfigFile, writeStorageFile, ensureConfigFileExist, readStorageFile, ensureStorageFileExist } from './runtime-file-utils.mjs'
|
||||
ensureConfigFileExist()
|
||||
ensureStorageFileExist()
|
||||
|
||||
const isRunFromUi = Boolean(process.env.MAIN_BOSSGEEKGO_UI_RUN_MODE)
|
||||
const isUiDev = process.env.NODE_ENV === 'development'
|
||||
export const autoStartChatEventBus = new EventEmitter()
|
||||
|
||||
let puppeteer, StealthPlugin
|
||||
export async function initPuppeteer () {
|
||||
@@ -43,12 +47,19 @@ export async function initPuppeteer () {
|
||||
StealthPlugin = importResult[1].default
|
||||
}
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
return {
|
||||
puppeteer,
|
||||
StealthPlugin
|
||||
}
|
||||
}
|
||||
|
||||
const { cookies: bossCookies } = readConfigFile('boss.json')
|
||||
const bossCookies = readStorageFile('boss-cookies.json')
|
||||
const bossLocalStorage = readStorageFile('boss-local-storage.json')
|
||||
|
||||
const targetCompanyList = readConfigFile('target-company-list.json')
|
||||
|
||||
const localStoragePageUrl = `https://www.zhipin.com/desktop/`
|
||||
const recommendJobPageUrl = `https://www.zhipin.com/web/geek/job-recommend`
|
||||
|
||||
const expectCompanySet = new Set(targetCompanyList)
|
||||
@@ -79,18 +90,39 @@ export async function mainLoop (hooks) {
|
||||
})
|
||||
|
||||
//set cookies
|
||||
const copiedBossCookies = JSON.parse(JSON.stringify(bossCookies))
|
||||
|
||||
hooks.cookieWillSet?.call(copiedBossCookies)
|
||||
for(let i = 0; i < copiedBossCookies.length; i++){
|
||||
await page.setCookie(copiedBossCookies[i]);
|
||||
hooks.cookieWillSet?.call(bossCookies)
|
||||
for(let i = 0; i < bossCookies.length; i++){
|
||||
await page.setCookie(bossCookies[i]);
|
||||
}
|
||||
|
||||
await setDomainLocalStorage(browser, localStoragePageUrl, bossLocalStorage)
|
||||
|
||||
let userInfoResponse
|
||||
await Promise.all([
|
||||
page.goto(recommendJobPageUrl, { timeout: 0 }),
|
||||
page.waitForResponse((response) => {
|
||||
if (response.url().startsWith('https://www.zhipin.com/wapi/zpuser/wap/getUserInfo.json')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}).then((res) => {
|
||||
return res.json()
|
||||
}).then((res) => {
|
||||
userInfoResponse = res
|
||||
}),
|
||||
page.waitForNavigation(),
|
||||
])
|
||||
hooks.pageLoaded?.call()
|
||||
hooks.userInfoResponse?.call(userInfoResponse)
|
||||
|
||||
if (userInfoResponse.code !== 0) {
|
||||
autoStartChatEventBus.emit('LOGIN_STATUS_INVALID', {
|
||||
userInfoResponse
|
||||
})
|
||||
writeStorageFile('boss-cookies.json', [])
|
||||
throw new Error("LOGIN_STATUS_INVALID")
|
||||
} else {
|
||||
await storeStorage(page).catch(() => void 0)
|
||||
}
|
||||
|
||||
const INIT_START_EXCEPT_JOB_INDEX = 1
|
||||
let currentExceptJobIndex = INIT_START_EXCEPT_JOB_INDEX
|
||||
@@ -123,6 +155,7 @@ export async function mainLoop (hooks) {
|
||||
return false
|
||||
}
|
||||
);
|
||||
await storeStorage(page).catch(() => void 0)
|
||||
await sleepWithRandomDelay(2000)
|
||||
}
|
||||
|
||||
@@ -242,6 +275,7 @@ export async function mainLoop (hooks) {
|
||||
if (res.code !== 0) {
|
||||
// startup chat error, may the chance of today has used out
|
||||
if (res.zpData.bizCode === 1 && res.zpData.bizData?.chatRemindDialog?.blockLevel === 0 && res.zpData.bizData?.chatRemindDialog?.content === `今日沟通人数已达上限,请明天再试`) {
|
||||
await storeStorage(page).catch(() => void 0)
|
||||
throw new Error('STARTUP_CHAT_ERROR_DUE_TO_TODAY_CHANCE_HAS_USED_OUT')
|
||||
} else {
|
||||
console.error(res)
|
||||
@@ -250,7 +284,8 @@ export async function mainLoop (hooks) {
|
||||
} else {
|
||||
hooks.newChatStartup?.call(jobData)
|
||||
blockBossNotNewChat.add(jobData.jobInfo.encryptUserId)
|
||||
|
||||
|
||||
await storeStorage(page).catch(() => void 0)
|
||||
await sleepWithRandomDelay(750)
|
||||
const closeDialogButtonProxy = await page.$('.greet-boss-dialog .greet-boss-footer .cancel-btn')
|
||||
await closeDialogButtonProxy.click()
|
||||
@@ -317,6 +352,23 @@ export async function mainLoop (hooks) {
|
||||
|
||||
export async function closeBrowserWindow () {
|
||||
browser?.close()
|
||||
browse = null
|
||||
browser = null
|
||||
page = null
|
||||
}
|
||||
|
||||
async function storeStorage (page) {
|
||||
const [
|
||||
cookies, localStorage
|
||||
] = await Promise.all([
|
||||
page.cookies(),
|
||||
page.evaluate(() => {
|
||||
return JSON.stringify(window.localStorage)
|
||||
}).then(res => JSON.parse(res))
|
||||
])
|
||||
return Promise.all(
|
||||
[
|
||||
writeStorageFile('boss-cookies.json', cookies),
|
||||
writeStorageFile('boss-local-storage.json', localStorage),
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import defaultDingtalkConf from './default-config-file/dingtalk.json' assert {ty
|
||||
import defaultBossConf from './default-config-file/boss.json' assert {type: 'json'}
|
||||
import defaultTargetCompanyListConf from './default-config-file/target-company-list.json' assert {type: 'json'}
|
||||
|
||||
import defaultBossCookieStorage from './default-storage-file/boss-cookies.json' assert { type: 'json' }
|
||||
import defaultBossLocalStorageStorage from './default-storage-file/boss-local-storage.json' assert { type: 'json' }
|
||||
export const configFileNameList = ['boss.json', 'dingtalk.json', 'target-company-list.json']
|
||||
|
||||
const defaultConfigFileContentMap = {
|
||||
@@ -20,7 +22,7 @@ const ensureRuntimeFolderPathExist = () => {
|
||||
if (!fs.existsSync(runtimeFolderPath)) {
|
||||
fs.mkdirSync(runtimeFolderPath)
|
||||
}
|
||||
;['config'].forEach(dirPath => {
|
||||
;['config', 'storage'].forEach(dirPath => {
|
||||
if (!fs.existsSync(
|
||||
path.join(runtimeFolderPath, dirPath)
|
||||
)) {
|
||||
@@ -52,8 +54,9 @@ export const ensureConfigFileExist = () => {
|
||||
}
|
||||
|
||||
export const readConfigFile = (fileName) => {
|
||||
const joinedPath = path.join(configFolderPath, fileName)
|
||||
if (!fs.existsSync(
|
||||
path.join(configFolderPath, fileName)
|
||||
joinedPath
|
||||
)) {
|
||||
ensureConfigFileExist()
|
||||
}
|
||||
@@ -61,10 +64,10 @@ export const readConfigFile = (fileName) => {
|
||||
let o
|
||||
try {
|
||||
o = JSON.parse(
|
||||
fs.readFileSync(path.join(configFolderPath, fileName))
|
||||
fs.readFileSync(joinedPath)
|
||||
)
|
||||
} catch {
|
||||
fs.unlinkSync(fs.readFileSync(path.join(configFolderPath, fileName)))
|
||||
fs.existsSync(joinedPath) && fs.unlinkSync(joinedPath)
|
||||
ensureConfigFileExist()
|
||||
o = JSON.parse(defaultConfigFileContentMap[fileName])
|
||||
}
|
||||
@@ -81,3 +84,60 @@ export const writeConfigFile = async (fileName, content) => {
|
||||
)
|
||||
}
|
||||
|
||||
export const storageFilePath = path.join(
|
||||
runtimeFolderPath,
|
||||
'storage'
|
||||
)
|
||||
export const storageFileNameList = ['boss-cookies.json', 'boss-local-storage.json']
|
||||
|
||||
const defaultStorageFileContentMap = {
|
||||
'boss-cookies.json': JSON.stringify(defaultBossCookieStorage),
|
||||
'boss-local-storage.json': JSON.stringify(defaultBossLocalStorageStorage)
|
||||
}
|
||||
export const ensureStorageFileExist = () => {
|
||||
ensureRuntimeFolderPathExist()
|
||||
;storageFileNameList.forEach(
|
||||
fileName => {
|
||||
if (!fs.existsSync(
|
||||
path.join(storageFilePath, fileName)
|
||||
)) {
|
||||
fs.writeFileSync(
|
||||
path.join(storageFilePath, fileName),
|
||||
defaultStorageFileContentMap[fileName]
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const readStorageFile = (fileName) => {
|
||||
const joinedPath = path.join(storageFilePath, fileName)
|
||||
|
||||
if (!fs.existsSync(
|
||||
joinedPath
|
||||
)) {
|
||||
ensureStorageFileExist()
|
||||
}
|
||||
|
||||
let o
|
||||
try {
|
||||
o = JSON.parse(
|
||||
fs.readFileSync(joinedPath)
|
||||
)
|
||||
} catch {
|
||||
fs.existsSync(joinedPath) && fs.unlinkSync(joinedPath)
|
||||
ensureStorageFileExist()
|
||||
o = JSON.parse(defaultStorageFileContentMap[fileName])
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
export const writeStorageFile = async (fileName, content) => {
|
||||
const filePath = path.join(storageFilePath, fileName)
|
||||
const fileContent = JSON.stringify(content)
|
||||
return fsPromise.writeFile(
|
||||
filePath,
|
||||
fileContent
|
||||
)
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,162 @@
|
||||
|
||||
import {
|
||||
initPuppeteer
|
||||
} from '@geekgeekrun/geek-auto-start-chat-with-boss/index.mjs'
|
||||
import {
|
||||
sleep,
|
||||
sleepWithRandomDelay
|
||||
} from '@geekgeekrun/utils/sleep.mjs'
|
||||
import extractZip from 'extract-zip'
|
||||
import { blockNavigation } from '@geekgeekrun/utils/puppeteer/block-navigation.mjs'
|
||||
import {
|
||||
writeStorageFile
|
||||
} from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path';
|
||||
import JSON5 from 'json5'
|
||||
import url from 'url';
|
||||
import packageJson from './package.json' assert {type: 'json'}
|
||||
|
||||
import { EventEmitter } from 'node:events'
|
||||
|
||||
export const loginEventBus = new EventEmitter()
|
||||
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||
const isRunFromUi = Boolean(process.env.MAIN_BOSSGEEKGO_UI_RUN_MODE)
|
||||
const isUiDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
const runtimeFolderPath = path.join(os.homedir(), '.geekgeekrun')
|
||||
const extensionDir = path.join(
|
||||
runtimeFolderPath,
|
||||
'chrome-extensions'
|
||||
)
|
||||
if (!fs.existsSync(
|
||||
runtimeFolderPath
|
||||
)) {
|
||||
fs.mkdirSync(runtimeFolderPath)
|
||||
}
|
||||
if (!fs.existsSync(extensionDir)) {
|
||||
fs.mkdirSync(extensionDir)
|
||||
}
|
||||
const editThisCookieExtensionPath = path.join(extensionDir, 'EditThisCookie')
|
||||
|
||||
let editThisCookieZipPath
|
||||
async function getEditThisCookieZipPath () {
|
||||
if (editThisCookieZipPath) {
|
||||
return editThisCookieZipPath
|
||||
}
|
||||
if (isRunFromUi) {
|
||||
const { app } = await import('electron')
|
||||
editThisCookieZipPath = path.join(app.getAppPath(), './node_modules', packageJson.name, 'extensions', 'EditThisCookie.zip')
|
||||
} else {
|
||||
editThisCookieZipPath = path.join(__dirname, 'extensions', 'EditThisCookie.zip')
|
||||
}
|
||||
return editThisCookieZipPath
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
if (!fs.existsSync(
|
||||
path.join(editThisCookieExtensionPath, 'manifest.json')
|
||||
)) {
|
||||
await extractZip(
|
||||
await getEditThisCookieZipPath(),
|
||||
{
|
||||
dir: extensionDir
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const { puppeteer } = await initPuppeteer()
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
args: [
|
||||
`--load-extension=${editThisCookieExtensionPath}`
|
||||
]
|
||||
})
|
||||
|
||||
const closeAttachedSet = new WeakSet()
|
||||
browser.on('targetcreated', async function closeNewTabs(target) {
|
||||
let targetBrowser = target.browser();
|
||||
const pages = await targetBrowser.pages()
|
||||
console.log(pages)
|
||||
for (let i = 1; i < pages.length; i++) {
|
||||
const page = pages[i]
|
||||
if (!closeAttachedSet.has(page)) {
|
||||
closeAttachedSet.add(page)
|
||||
page.once('domcontentloaded', () => {
|
||||
page.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const [page] = await browser.pages();
|
||||
|
||||
page.once('close', async () => {
|
||||
browser.close()
|
||||
if (isRunFromUi) {
|
||||
const electron = await import('electron')
|
||||
electron.app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
const { dispose: disposeNavigationLock } = await blockNavigation(page, (req) => !req.url().startsWith('https://www.zhipin.com'))
|
||||
await page.goto('https://www.zhipin.com/web/user/');
|
||||
|
||||
const loginSuccessPromiseList = [
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().startsWith('https://www.zhipin.com/wapi/zppassport/qrcode/loginConfirm'),
|
||||
{
|
||||
timeout: 0
|
||||
}
|
||||
),
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().startsWith('https://www.zhipin.com/wapi/zppassport/qrcode/dispatcher'),
|
||||
{
|
||||
timeout: 0
|
||||
}
|
||||
),
|
||||
page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().startsWith('https://www.zhipin.com/wapi/zppassport/login/phoneV2'),
|
||||
{ timeout: 0 }
|
||||
)
|
||||
]
|
||||
|
||||
Promise.all([
|
||||
Promise.race(loginSuccessPromiseList),
|
||||
page.waitForNavigation({
|
||||
timeout: 0
|
||||
}),
|
||||
]).then(async () => {
|
||||
await sleep(2000)
|
||||
const headerLogoAnchorHandler = await page.$('.header-home-logo')
|
||||
return Promise.all([
|
||||
headerLogoAnchorHandler ? headerLogoAnchorHandler.click() : page.goto('https://www.zhipin.com/'),
|
||||
page.waitForNavigation({
|
||||
timeout: 0,
|
||||
})
|
||||
])
|
||||
}).then(async () => {
|
||||
if (
|
||||
page.url().startsWith('https://www.zhipin.com/web/common/security-check.html')
|
||||
) {
|
||||
await page.waitForNavigation({
|
||||
timeout: 0,
|
||||
})
|
||||
}
|
||||
await sleep(2000)
|
||||
const cookies = await page.cookies()
|
||||
loginEventBus.emit(
|
||||
'cookie-collected',
|
||||
cookies
|
||||
)
|
||||
return writeStorageFile('boss-cookies.json', cookies)
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
351
packages/launch-bosszhipin-login-page-with-preload-extension/package-lock.json
generated
Normal file
351
packages/launch-bosszhipin-login-page-with-preload-extension/package-lock.json
generated
Normal file
@@ -0,0 +1,351 @@
|
||||
{
|
||||
"name": "@geekgeekrun/launch-browser-with-preload-extension",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@geekgeekrun/launch-browser-with-preload-extension",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"node-fetch": "^3.3.2",
|
||||
"unzipper": "^0.10.14"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/big-integer": {
|
||||
"version": "1.6.52",
|
||||
"resolved": "https://registry.npmmirror.com/big-integer/-/big-integer-1.6.52.tgz",
|
||||
"integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/binary": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/binary/-/binary-0.3.0.tgz",
|
||||
"integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
|
||||
"dependencies": {
|
||||
"buffers": "~0.1.1",
|
||||
"chainsaw": "~0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/bluebird": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.4.7.tgz",
|
||||
"integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-indexof-polyfill": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
|
||||
"integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/buffers": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/buffers/-/buffers-0.1.1.tgz",
|
||||
"integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
|
||||
"engines": {
|
||||
"node": ">=0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chainsaw": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/chainsaw/-/chainsaw-0.1.0.tgz",
|
||||
"integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
|
||||
"dependencies": {
|
||||
"traverse": ">=0.3.0 <0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer2": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/duplexer2/-/duplexer2-0.1.4.tgz",
|
||||
"integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
|
||||
"dependencies": {
|
||||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fstream": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmmirror.com/fstream/-/fstream-1.0.12.tgz",
|
||||
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"inherits": "~2.0.0",
|
||||
"mkdirp": ">=0.5 0",
|
||||
"rimraf": "2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/listenercount": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/listenercount/-/listenercount-1.0.1.tgz",
|
||||
"integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ=="
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/traverse": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmmirror.com/traverse/-/traverse-0.3.9.tgz",
|
||||
"integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/unzipper": {
|
||||
"version": "0.10.14",
|
||||
"resolved": "https://registry.npmmirror.com/unzipper/-/unzipper-0.10.14.tgz",
|
||||
"integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==",
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.17",
|
||||
"binary": "~0.3.0",
|
||||
"bluebird": "~3.4.1",
|
||||
"buffer-indexof-polyfill": "~1.0.0",
|
||||
"duplexer2": "~0.1.4",
|
||||
"fstream": "^1.0.12",
|
||||
"graceful-fs": "^4.2.2",
|
||||
"listenercount": "~1.0.1",
|
||||
"readable-stream": "~2.3.6",
|
||||
"setimmediate": "~1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "launch-bosszhipin-login-page-with-preload-extension",
|
||||
"module": "./index.mjs",
|
||||
"type": "module",
|
||||
"scripts": {},
|
||||
"author": "geekgeekrun",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@geekgeekrun/geek-auto-start-chat-with-boss": "workspace:*",
|
||||
"@geekgeekrun/utils": "workspace:*",
|
||||
"extract-zip": "^2.0.1",
|
||||
"node-fetch": "^3.3.2"
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { get__dirname } from '@geekgeekrun/utils/legacy-path.mjs';
|
||||
import JSON5 from 'json5'
|
||||
import { readConfigFile } from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||
const { cookies: bossCookies } = readConfigFile('boss.json')
|
||||
import { readConfigFile, readStorageFile } from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||
const bossCookies = readStorageFile('boss-cookies.json')
|
||||
const { groupRobotAccessToken: dingTalkAccessToken } = readConfigFile('dingtalk.json')
|
||||
|
||||
const initPlugins = (hooks) => {
|
||||
|
||||
@@ -10,7 +10,8 @@ files:
|
||||
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
- 'resources/**'
|
||||
- 'node_modules/@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension/**'
|
||||
extraResources:
|
||||
- external-node-runtime-dependencies/**
|
||||
win:
|
||||
|
||||
@@ -14,7 +14,7 @@ export default defineConfig({
|
||||
},
|
||||
plugins: [
|
||||
externalizeDepsPlugin({
|
||||
exclude: ['@geekgeekrun/geek-auto-start-chat-with-boss', '@geekgeekrun/dingtalk-plugin', '@geekgeekrun/utils', 'find-chrome-bin']
|
||||
exclude: ['@geekgeekrun/geek-auto-start-chat-with-boss', '@geekgeekrun/dingtalk-plugin', '@geekgeekrun/utils', 'find-chrome-bin', '@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension']
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"dev": "electron-vite dev",
|
||||
"dev:geek-auto-start-chat-with-boss-only": "cross-env MAIN_BOSSGEEKGO_UI_RUN_MODE=geekAutoStartWithBoss electron-vite dev",
|
||||
"dev:check-and-download-dependencies-for-init-only": "cross-env MAIN_BOSSGEEKGO_UI_RUN_MODE=checkAndDownloadDependenciesForInit electron-vite dev",
|
||||
"dev:launch-bosszhipin-login-page-with-preload-extension-only": "cross-env MAIN_BOSSGEEKGO_UI_RUN_MODE=launchBossZhipinLoginPageWithPreloadExtension electron-vite dev",
|
||||
"build": "electron-vite build",
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix",
|
||||
@@ -19,13 +20,15 @@
|
||||
"build:unpack": "npm run build && electron-builder --dir",
|
||||
"build:win": "npm run build && electron-builder --win",
|
||||
"build:mac": "npm run build && electron-builder --mac",
|
||||
"build:linux": "npm run build && electron-builder --linux"
|
||||
"build:linux": "npm run build && electron-builder --linux",
|
||||
"install": "cd ./external-node-runtime-dependencies && cross-env PUPPETEER_SKIP_DOWNLOAD=geekAutoStartWithBoss npm install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron-toolkit/preload": "^3.0.0",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@geekgeekrun/dingtalk-plugin": "workspace:*",
|
||||
"@geekgeekrun/geek-auto-start-chat-with-boss": "workspace:*",
|
||||
"@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension": "workspace:*",
|
||||
"@geekgeekrun/utils": "workspace:*",
|
||||
"@puppeteer/browsers": "^2.0.0",
|
||||
"JSONStream": "^1.3.5",
|
||||
|
||||
27
packages/ui/src/common/utils/cookie.ts
Normal file
27
packages/ui/src/common/utils/cookie.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export const checkCookieListFormat = (cookies: Array<Record<string, string>>) => {
|
||||
const allExpectKeySet = new Set([
|
||||
'name',
|
||||
'value',
|
||||
'domain',
|
||||
'path',
|
||||
'secure',
|
||||
'session',
|
||||
'httpOnly'
|
||||
])
|
||||
return Array.isArray(cookies) &&
|
||||
cookies.length &&
|
||||
cookies.every((it) => {
|
||||
const currentOwnedKeySet = new Set(Object.keys(it))
|
||||
if (currentOwnedKeySet.size < allExpectKeySet.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
const allExpectKeyArr = [...allExpectKeySet]
|
||||
for (let i = 0; i < allExpectKeyArr.length; i++) {
|
||||
if (!currentOwnedKeySet.has(allExpectKeyArr[i])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -15,7 +15,7 @@ const initPlugins = (hooks) => {
|
||||
let isParentProcessDisconnect = false
|
||||
|
||||
export const runAutoChat = async () => {
|
||||
const { initPuppeteer, mainLoop, closeBrowserWindow } = await import(
|
||||
const { initPuppeteer, mainLoop, closeBrowserWindow, autoStartChatEventBus } = await import(
|
||||
'@geekgeekrun/geek-auto-start-chat-with-boss/index.mjs'
|
||||
)
|
||||
process.on('disconnect', () => {
|
||||
@@ -73,16 +73,27 @@ export const runAutoChat = async () => {
|
||||
type: 'GEEK_AUTO_START_CHAT_WITH_BOSS_STARTED' //geek-auto-start-chat-with-boss-started
|
||||
}) + '\r\n'
|
||||
)
|
||||
while (!([isParentProcessDisconnect].includes(true))) {
|
||||
|
||||
autoStartChatEventBus.once('LOGIN_STATUS_INVALID', () => {
|
||||
pipeWriteRegardlessError(
|
||||
pipe,
|
||||
JSON.stringify({
|
||||
type: 'LOGIN_STATUS_INVALID' //geek-auto-start-chat-with-boss-started
|
||||
}) + '\r\n'
|
||||
)
|
||||
})
|
||||
|
||||
while (![isParentProcessDisconnect].includes(true)) {
|
||||
try {
|
||||
await mainLoop(hooks)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
// if(err instanceof Error && err.message.includes('ERR_MODULE_NOT_FOUND')) {
|
||||
// throw err
|
||||
// } else {
|
||||
void err
|
||||
// }
|
||||
if (err instanceof Error && err.message.includes('LOGIN_STATUS_INVALID')) {
|
||||
process.exit(2)
|
||||
break
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
closeBrowserWindow()
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { app } from 'electron'
|
||||
import { main, loginEventBus } from '@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension'
|
||||
import { pipeWriteRegardlessError } from './utils/pipe'
|
||||
import fs from "node:fs";
|
||||
|
||||
export enum DOWNLOAD_ERROR_EXIT_CODE {
|
||||
NO_ERROR = 0,
|
||||
DOWNLOAD_ERROR = 1
|
||||
}
|
||||
|
||||
export const launchBossZhipinLoginPageWithPreloadExtension = async () => {
|
||||
process.on('disconnect', () => app.exit())
|
||||
app.dock?.hide()
|
||||
let pipe: null | fs.WriteStream = null
|
||||
try {
|
||||
pipe = fs.createWriteStream(null, { fd: 3 })
|
||||
} catch {
|
||||
console.warn('pipe is not available')
|
||||
}
|
||||
pipeWriteRegardlessError(
|
||||
pipe,
|
||||
JSON.stringify({
|
||||
type: 'INITIALIZE_PUPPETEER'
|
||||
}) + '\r\n'
|
||||
)
|
||||
const { initPuppeteer } = await import('@geekgeekrun/geek-auto-start-chat-with-boss/index.mjs')
|
||||
try {
|
||||
await initPuppeteer()
|
||||
pipeWriteRegardlessError(
|
||||
pipe,
|
||||
JSON.stringify({
|
||||
type: 'PUPPETEER_INITIALIZE_SUCCESSFULLY'
|
||||
}) + '\r\n'
|
||||
)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
app.exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
loginEventBus.once('cookie-collected', (cookies) => {
|
||||
pipeWriteRegardlessError(
|
||||
pipe,
|
||||
JSON.stringify({
|
||||
type: 'BOSS_ZHIPIN_COOKIE_COLLECTED',
|
||||
cookies
|
||||
}) + '\r\n'
|
||||
)
|
||||
})
|
||||
main()
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { runAutoChat } from './flow/GEEK_AUTO_START_CHAT_WITH_BOSS'
|
||||
import { openSettingWindow } from './flow/OPEN_SETTING_WINDOW'
|
||||
import { checkAndDownloadDependenciesForInit } from './flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index';
|
||||
import { checkAndDownloadDependenciesForInit } from './flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index'
|
||||
import { launchBossZhipinLoginPageWithPreloadExtension } from './flow/LAUNCH_BOSS_ZHIPIN_LOGIN_PAGE_WITH_PRELOAD_EXTENSION'
|
||||
|
||||
const runMode = process.env.MAIN_BOSSGEEKGO_UI_RUN_MODE
|
||||
switch (runMode) {
|
||||
@@ -12,6 +13,10 @@ switch (runMode) {
|
||||
checkAndDownloadDependenciesForInit()
|
||||
break
|
||||
}
|
||||
case 'launchBossZhipinLoginPageWithPreloadExtension': {
|
||||
launchBossZhipinLoginPageWithPreloadExtension()
|
||||
break
|
||||
}
|
||||
default: {
|
||||
openSettingWindow()
|
||||
break
|
||||
|
||||
@@ -3,17 +3,23 @@ import path from 'path'
|
||||
import * as childProcess from 'node:child_process'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import {
|
||||
readConfigFile,
|
||||
configFileNameList,
|
||||
ensureConfigFileExist,
|
||||
writeConfigFile
|
||||
ensureStorageFileExist,
|
||||
|
||||
configFileNameList,
|
||||
readConfigFile,
|
||||
writeConfigFile,
|
||||
readStorageFile,
|
||||
writeStorageFile
|
||||
} from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
|
||||
import { ChildProcess } from 'child_process'
|
||||
import * as JSONStream from 'JSONStream'
|
||||
import { checkCookieListFormat } from '../../common/utils/cookie'
|
||||
import {
|
||||
DOWNLOAD_ERROR_EXIT_CODE,
|
||||
getAnyAvailablePuppeteerExecutable
|
||||
} from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES'
|
||||
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
|
||||
export function createMainWindow(): void {
|
||||
@@ -25,8 +31,8 @@ export function createMainWindow(): void {
|
||||
autoHideMenuBar: true,
|
||||
...(process.platform === 'linux'
|
||||
? {
|
||||
/* icon */
|
||||
}
|
||||
/* icon */
|
||||
}
|
||||
: {}),
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, '../preload/index.js'),
|
||||
@@ -53,15 +59,24 @@ export function createMainWindow(): void {
|
||||
mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
|
||||
}
|
||||
|
||||
ipcMain.on('open-external-link', (_, link) => {
|
||||
shell.openExternal(link, {
|
||||
activate: true
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.handle('fetch-config-file-content', async () => {
|
||||
const fileContentList = configFileNameList.map((fileName) => {
|
||||
const configFileContentList = configFileNameList.map((fileName) => {
|
||||
return readConfigFile(fileName)
|
||||
})
|
||||
const result = {}
|
||||
const result = {
|
||||
config: {},
|
||||
}
|
||||
|
||||
configFileNameList.forEach((fileName, index) => {
|
||||
result[fileName] = fileContentList[index]
|
||||
result.config[fileName] = configFileContentList[index]
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
@@ -72,16 +87,23 @@ export function createMainWindow(): void {
|
||||
const dingtalkConfig = readConfigFile('dingtalk.json')
|
||||
dingtalkConfig.groupRobotAccessToken = payload.dingtalkRobotAccessToken
|
||||
|
||||
const bossZhipinConfig = readConfigFile('boss.json')
|
||||
bossZhipinConfig.cookies = JSON.parse(payload.bossZhipinCookies)
|
||||
|
||||
return await Promise.all([
|
||||
writeConfigFile('boss.json', bossZhipinConfig),
|
||||
writeConfigFile('dingtalk.json', dingtalkConfig),
|
||||
writeConfigFile('target-company-list.json', payload.expectCompanies.split(','))
|
||||
])
|
||||
})
|
||||
|
||||
ipcMain.handle('read-storage-file', async (ev, payload) => {
|
||||
ensureStorageFileExist()
|
||||
return await readStorageFile(payload.fileName)
|
||||
})
|
||||
|
||||
ipcMain.handle('write-storage-file', async (ev, payload) => {
|
||||
ensureStorageFileExist()
|
||||
|
||||
return await writeStorageFile(payload.fileName, JSON.parse(payload.data))
|
||||
})
|
||||
|
||||
// const currentExecutablePath = app.getPath('exe')
|
||||
// console.log(currentExecutablePath)
|
||||
|
||||
@@ -102,13 +124,18 @@ export function createMainWindow(): void {
|
||||
})
|
||||
console.log(subProcessOfPuppeteer)
|
||||
return new Promise((resolve, reject) => {
|
||||
subProcessOfPuppeteer!.stdio[3]!.pipe(JSONStream.parse()).on('data', (raw) => {
|
||||
subProcessOfPuppeteer!.stdio[3]!.pipe(JSONStream.parse()).on('data', async (raw) => {
|
||||
const data = raw
|
||||
switch (data.type) {
|
||||
case 'GEEK_AUTO_START_CHAT_WITH_BOSS_STARTED': {
|
||||
resolve(data)
|
||||
break
|
||||
}
|
||||
case 'LOGIN_STATUS_INVALID': {
|
||||
await sleep(500)
|
||||
mainWindow?.webContents.send('check-boss-zhipin-cookie-file')
|
||||
return
|
||||
}
|
||||
default: {
|
||||
return
|
||||
}
|
||||
@@ -195,11 +222,62 @@ export function createMainWindow(): void {
|
||||
mainWindow?.webContents.send('geek-auto-start-chat-with-boss-stopping')
|
||||
subProcessOfPuppeteer?.kill('SIGINT')
|
||||
})
|
||||
ipcMain.on('open-project-homepage-on-github', () => {
|
||||
shell.openExternal(`https://github.com/geekgeekrun`, {
|
||||
activate: true
|
||||
|
||||
let subProcessOfBossZhipinLoginPageWithPreloadExtension: ChildProcess | null = null
|
||||
ipcMain.on('launch-bosszhipin-login-page-with-preload-extension', async () => {
|
||||
try {
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension?.kill()
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
const subProcessEnv = {
|
||||
...process.env,
|
||||
MAIN_BOSSGEEKGO_UI_RUN_MODE: 'launchBossZhipinLoginPageWithPreloadExtension',
|
||||
PUPPETEER_EXECUTABLE_PATH: (await getAnyAvailablePuppeteerExecutable())!.executablePath
|
||||
}
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension = childProcess.spawn(
|
||||
process.argv[0],
|
||||
process.argv.slice(1),
|
||||
{
|
||||
env: subProcessEnv,
|
||||
stdio: [null, null, null, 'pipe', 'ipc']
|
||||
}
|
||||
)
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension!.stdio[3]!.pipe(JSONStream.parse()).on(
|
||||
'data',
|
||||
(raw) => {
|
||||
const data = raw
|
||||
switch (data.type) {
|
||||
case 'BOSS_ZHIPIN_COOKIE_COLLECTED': {
|
||||
mainWindow?.webContents.send(data.type, data)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension!.once('exit', () => {
|
||||
mainWindow?.webContents.send('BOSS_ZHIPIN_LOGIN_PAGE_CLOSED')
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension = null
|
||||
})
|
||||
})
|
||||
ipcMain.on('kill-bosszhipin-login-page-with-preload-extension', async () => {
|
||||
try {
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension?.kill()
|
||||
} catch {
|
||||
//
|
||||
} finally {
|
||||
subProcessOfBossZhipinLoginPageWithPreloadExtension = null
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('check-boss-zhipin-cookie-file', () => {
|
||||
const cookies = readStorageFile('boss-cookies.json')
|
||||
return checkCookieListFormat(cookies)
|
||||
})
|
||||
|
||||
mainWindow!.once('closed', () => {
|
||||
mainWindow = null
|
||||
|
||||
@@ -26,7 +26,8 @@ const props = defineProps({
|
||||
dependenciesStatus: {
|
||||
type: Object as PropType<Record<string, boolean>>,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
processWaitee: Object
|
||||
})
|
||||
|
||||
// shallow copy
|
||||
@@ -75,6 +76,7 @@ const processTasks = async () => {
|
||||
try {
|
||||
p.then(() => {
|
||||
if (!promiseList.length) {
|
||||
props.processWaitee?.resolve?.()
|
||||
props.dispose?.()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createApp } from 'vue'
|
||||
import ElementPlus from 'element-plus'
|
||||
import DependenciesSetupProgressIndicatorDialog from './index.vue'
|
||||
|
||||
export const mountGlobalDialog = (dependenciesStatus: Record<string, boolean>) => {
|
||||
export const mountGlobalDialog = (o: { dependenciesStatus: Record<string, boolean>, processWaitee? }) => {
|
||||
const containerElId = `elForDependenciesSetupProgressIndicatorDialog`
|
||||
|
||||
if (document.getElementById(containerElId)) {
|
||||
@@ -28,7 +28,8 @@ export const mountGlobalDialog = (dependenciesStatus: Record<string, boolean>) =
|
||||
dispose()
|
||||
},
|
||||
dispose,
|
||||
dependenciesStatus
|
||||
dependenciesStatus: o?.dependenciesStatus,
|
||||
processWaitee: o?.processWaitee
|
||||
}).use(ElementPlus)
|
||||
app.mount(containerEl)
|
||||
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-bind="$attrs"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="!cookieInvalid"
|
||||
title="Boss直聘 Cookie助手"
|
||||
:width="720"
|
||||
top="20px"
|
||||
lock-scroll
|
||||
:show-close="!cookieInvalid"
|
||||
>
|
||||
<el-alert
|
||||
v-if="cookieInvalid"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
title="需要获取您的Boss直聘Cookie才能继续"
|
||||
>
|
||||
由于您是首次使用本程序,或者您之前使用的Boss直聘账号登录状态失效,因此您需要重新获取登录凭证。
|
||||
</el-alert>
|
||||
<div ml1em mt1em line-height-normal>
|
||||
如果您了解如何获取Cookie、了解有效的Cookie格式,可以直接在下方输入框中进行编辑。<br />
|
||||
手动编辑较为麻烦,建议您打开已登录过Boss直聘的浏览器,使用
|
||||
<a
|
||||
color-blue
|
||||
decoration-none
|
||||
href="javascript:void(0)"
|
||||
@click.prevent="handleEditThisCookieExtensionStoreLinkClick"
|
||||
>EditThisCookie 扩展程序</a
|
||||
>
|
||||
复制Cookie,然后粘贴在下方输入框中。<br />
|
||||
格式为被序列化为JSON的数组,不含两侧引号。
|
||||
</div>
|
||||
<br />
|
||||
<div ml1em line-height-normal>
|
||||
如果您不了解Cookie相关概念,或者不能访问Chrome扩展程序商店下载EditThisCookie来获取Cookie,请按照以下步骤进行操作:
|
||||
</div>
|
||||
<ol lh-2em mt-0>
|
||||
<li>
|
||||
<el-button size="small" type="primary" font-size-inherit @click="handleClickLaunchLogin"
|
||||
>点击此处</el-button
|
||||
>
|
||||
启动浏览器
|
||||
</li>
|
||||
<li>按照正常流程,通过 <b>短信验证码/二维码/微信小程序</b> 登录您的Boss直聘账号</li>
|
||||
<li>接下来将自动进行一些页面跳转,最终将会停留在首页</li>
|
||||
<li>
|
||||
登录后预计5-10秒内(具体取决于您的网速),您的Cookie将被自动填入下方输入框。
|
||||
<details>
|
||||
<summary color-orange cursor-pointer>我已完成登录,但Cookie一直没出现?</summary>
|
||||
<div ml-2em max-h-200px of-auto>
|
||||
如果您确实已经在打开浏览器中看到您已登录了Boss直聘,请尝试按照如图所示方式复制Cookie:
|
||||
<figure>
|
||||
<figcaption>依次点击浏览器右上角“扩展程序”图标、“EditThisCookie”图标</figcaption>
|
||||
<img block max-w-full src="./resources/copy-cookie-step-1.png" />
|
||||
</figure>
|
||||
<figure>
|
||||
<figcaption>点击“EditThisCookie”弹出框中的“Export”按钮</figcaption>
|
||||
<img block max-w-full src="./resources/copy-cookie-step-2.png" />
|
||||
</figure>
|
||||
<figure>
|
||||
<figcaption>在下方输入框执行粘贴操作。</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</details>
|
||||
</li>
|
||||
</ol>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
inline-message
|
||||
:model="formContent"
|
||||
label-position="top"
|
||||
:rules="formRules"
|
||||
class="cookie-form"
|
||||
>
|
||||
<el-form-item prop="collectedCookies" mb-0>
|
||||
<el-input
|
||||
v-model="formContent.collectedCookies"
|
||||
type="textarea"
|
||||
:autosize="{
|
||||
minRows: 10,
|
||||
maxRows: 10
|
||||
}"
|
||||
font-size-12px
|
||||
@input="hasUserMutateInput = true"
|
||||
></el-input>
|
||||
<el-alert
|
||||
v-if="loginCookieWaitingStatus === LOGIN_COOKIE_WAITING_STATUS.WAITING_FOR_LOGIN"
|
||||
:closable="false"
|
||||
>正在等待登录……</el-alert
|
||||
>
|
||||
<el-alert
|
||||
v-if="loginCookieWaitingStatus === LOGIN_COOKIE_WAITING_STATUS.COOKIE_COLLECTED"
|
||||
:closable="false"
|
||||
type="success"
|
||||
>已获取到Cookie<template v-if="hasUserMutateInput"
|
||||
>;看起来您似乎正在尝试手动输入Cookie?<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
font-size-inherit
|
||||
@click="fillCollectedCookie"
|
||||
>使用获取到的Cookie</el-button
|
||||
></template
|
||||
></el-alert
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button v-if="!cookieInvalid" @click="dispose">关闭</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">保存Cookie</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElForm, ElMessage } from 'element-plus'
|
||||
import { ref, onUnmounted, onMounted } from 'vue'
|
||||
import { checkCookieListFormat } from '../../../../common/utils/cookie'
|
||||
|
||||
const props = defineProps({
|
||||
dispose: Function,
|
||||
processWaitee: Object
|
||||
})
|
||||
|
||||
const cookieInvalid = ref(false)
|
||||
|
||||
enum LOGIN_COOKIE_WAITING_STATUS {
|
||||
INIT,
|
||||
WAITING_FOR_LOGIN,
|
||||
COOKIE_COLLECTED
|
||||
}
|
||||
const loginCookieWaitingStatus = ref(LOGIN_COOKIE_WAITING_STATUS.INIT)
|
||||
|
||||
const formRef = ref<InstanceType<typeof ElForm>>()
|
||||
const formContent = ref({
|
||||
collectedCookies: ''
|
||||
})
|
||||
|
||||
const formRules = {
|
||||
collectedCookies: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入Cookie'
|
||||
},
|
||||
{
|
||||
trigger: 'blur',
|
||||
validator(rule, val, cb) {
|
||||
let arr
|
||||
try {
|
||||
arr = JSON.parse(val)
|
||||
} catch (err) {
|
||||
cb(
|
||||
new Error(
|
||||
`JSON格式无效 - 存在语法错误: ${err.message};建议使用EditThisCookie扩展程序进行复制。`
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (!checkCookieListFormat(JSON.parse(formContent.value.collectedCookies))) {
|
||||
cb(new Error(`Cookie格式无效 - 部分字段缺失;建议使用EditThisCookie扩展程序进行复制。`))
|
||||
return
|
||||
}
|
||||
cb()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const hasUserMutateInput = ref(false)
|
||||
const collectedCookie = ref()
|
||||
const handleCookieCollected = (_, payload) => {
|
||||
loginCookieWaitingStatus.value = LOGIN_COOKIE_WAITING_STATUS.COOKIE_COLLECTED
|
||||
collectedCookie.value = payload.cookies
|
||||
if (!hasUserMutateInput.value) {
|
||||
fillCollectedCookie()
|
||||
}
|
||||
}
|
||||
const fillCollectedCookie = () => {
|
||||
if (loginCookieWaitingStatus.value !== LOGIN_COOKIE_WAITING_STATUS.COOKIE_COLLECTED) {
|
||||
return
|
||||
}
|
||||
formContent.value.collectedCookies = JSON.stringify(collectedCookie.value, null, 2)
|
||||
hasUserMutateInput.value = false
|
||||
}
|
||||
|
||||
const handleClickLaunchLogin = () => {
|
||||
electron.ipcRenderer.send('launch-bosszhipin-login-page-with-preload-extension')
|
||||
loginCookieWaitingStatus.value = LOGIN_COOKIE_WAITING_STATUS.WAITING_FOR_LOGIN
|
||||
}
|
||||
|
||||
const handleEditThisCookieExtensionStoreLinkClick = () => {
|
||||
electron.ipcRenderer.send(
|
||||
'open-external-link',
|
||||
'https://chromewebstore.google.com/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg'
|
||||
)
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
await formRef.value!.validate()
|
||||
await electron.ipcRenderer.invoke('write-storage-file', {
|
||||
fileName: 'boss-cookies.json',
|
||||
data: formContent.value.collectedCookies
|
||||
})
|
||||
ElMessage.success('Boss直聘 Cookie 保存成功')
|
||||
props.processWaitee?.resolve?.()
|
||||
props.dispose()
|
||||
}
|
||||
|
||||
const handleBossZhipinLoginPageClosed = () => {
|
||||
if (loginCookieWaitingStatus.value === LOGIN_COOKIE_WAITING_STATUS.WAITING_FOR_LOGIN) {
|
||||
loginCookieWaitingStatus.value = LOGIN_COOKIE_WAITING_STATUS.INIT
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
electron.ipcRenderer.once('BOSS_ZHIPIN_COOKIE_COLLECTED', handleCookieCollected)
|
||||
electron.ipcRenderer.on('BOSS_ZHIPIN_LOGIN_PAGE_CLOSED', handleBossZhipinLoginPageClosed)
|
||||
|
||||
const cookieFileContent = await electron.ipcRenderer.invoke('read-storage-file', {
|
||||
fileName: 'boss-cookies.json'
|
||||
})
|
||||
if (checkCookieListFormat(cookieFileContent)) {
|
||||
formContent.value.collectedCookies = JSON.stringify(cookieFileContent, null, 2)
|
||||
} else {
|
||||
cookieInvalid.value = true
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
electron.ipcRenderer.removeListener('BOSS_ZHIPIN_COOKIE_COLLECTED', handleCookieCollected)
|
||||
electron.ipcRenderer.removeListener(
|
||||
'BOSS_ZHIPIN_LOGIN_PAGE_CLOSED',
|
||||
handleBossZhipinLoginPageClosed
|
||||
)
|
||||
electron.ipcRenderer.send('kill-bosszhipin-login-page-with-preload-extension')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.cookie-form.el-form {
|
||||
.el-form-item__error--inline {
|
||||
margin-left: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,38 @@
|
||||
import { createApp } from 'vue'
|
||||
import ElementPlus from 'element-plus'
|
||||
import WaitForLogin from './index.vue'
|
||||
|
||||
export const mountGlobalDialog = (o: { processWaitee? }) => {
|
||||
const containerElId = `elForWaitForLogin`
|
||||
|
||||
if (document.getElementById(containerElId)) {
|
||||
return
|
||||
}
|
||||
let containerEl: null | HTMLElement = (() => {
|
||||
const el = document.createElement('div')
|
||||
el.id = containerElId
|
||||
return el
|
||||
})()
|
||||
document.body.append(containerEl)
|
||||
|
||||
const dispose = () => {
|
||||
app?.unmount()
|
||||
containerEl?.remove()
|
||||
|
||||
app = null
|
||||
containerEl = null
|
||||
}
|
||||
let app: null | ReturnType<typeof createApp> = createApp(WaitForLogin, {
|
||||
modelValue: true,
|
||||
onClosed() {
|
||||
dispose()
|
||||
},
|
||||
dispose,
|
||||
processWaitee: o?.processWaitee
|
||||
}).use(ElementPlus)
|
||||
app.mount(containerEl)
|
||||
|
||||
return {
|
||||
dispose
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
@@ -1,15 +1,10 @@
|
||||
<template>
|
||||
<div class="form-wrap">
|
||||
<el-form ref="formRef" :model="formContent" label-position="top" :rules="formRules">
|
||||
<el-form-item
|
||||
label="BOSS直聘 Cookie (使用EditThisCookie扩展程序,从你已登录过BOSS直聘的浏览器复制)"
|
||||
prop="bossZhipinCookies"
|
||||
>
|
||||
<el-input
|
||||
v-model="formContent.bossZhipinCookies"
|
||||
:autosize="{ minRows: 4 }"
|
||||
type="textarea"
|
||||
/>
|
||||
<el-form-item label="BOSS直聘 Cookie">
|
||||
<el-button size="small" type="primary" font-size-inherit @click="handleClickLaunchLogin"
|
||||
>编辑Cookie</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item label="钉钉机器人 AccessToken" prop="dingtalkRobotAccessToken">
|
||||
<el-input v-model="formContent.dingtalkRobotAccessToken" />
|
||||
@@ -32,47 +27,23 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import JSON5 from 'json5'
|
||||
import { ElForm, ElMessage } from 'element-plus'
|
||||
import router from '../../router/index'
|
||||
import { mountGlobalDialog as mountDependenciesSetupProgressIndicatorDialog } from '@renderer/features/DependenciesSetupProgressIndicatorDialog/operations'
|
||||
import { mountGlobalDialog as mountWaitForLoginDialog } from '@renderer/features/WaitForLoginDialog/operations'
|
||||
|
||||
const formContent = ref({
|
||||
bossZhipinCookies: '',
|
||||
dingtalkRobotAccessToken: '',
|
||||
expectCompanies: ''
|
||||
})
|
||||
|
||||
electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
||||
console.log(res)
|
||||
formContent.value.bossZhipinCookies = JSON.stringify(res['boss.json'].cookies, null, 2)
|
||||
formContent.value.dingtalkRobotAccessToken = res['dingtalk.json']['groupRobotAccessToken']
|
||||
formContent.value.expectCompanies = res['target-company-list.json'].join(',')
|
||||
formContent.value.dingtalkRobotAccessToken = res.config['dingtalk.json']['groupRobotAccessToken']
|
||||
formContent.value.expectCompanies = res.config['target-company-list.json'].join(',')
|
||||
})
|
||||
|
||||
const formRules = {
|
||||
bossZhipinCookies: [
|
||||
{
|
||||
required: true
|
||||
},
|
||||
{
|
||||
trigger: 'blur',
|
||||
validator(rule, val, cb) {
|
||||
let arr
|
||||
try {
|
||||
arr = JSON5.parse(val)
|
||||
} catch (err) {
|
||||
cb(new Error(`JSON content is invalid: ${err.message}`))
|
||||
return
|
||||
}
|
||||
if (!Array.isArray(arr) || !arr.length) {
|
||||
cb(new Error(`Invalid cookies. Please copy with EditThisCookie extension`))
|
||||
return
|
||||
}
|
||||
cb()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const formRef = ref<InstanceType<typeof ElForm>>()
|
||||
@@ -116,11 +87,15 @@ const handleExpectCompaniesInputBlur = (event) => {
|
||||
.filter(Boolean)
|
||||
.join(',')
|
||||
}
|
||||
|
||||
const handleClickLaunchLogin = () => {
|
||||
mountWaitForLoginDialog()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-wrap {
|
||||
padding-top: 100px;
|
||||
padding-top: 60px;
|
||||
margin: 0 auto;
|
||||
max-width: 640px;
|
||||
.last-form-item {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template><RouterView /></template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted } from 'vue'
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
import { mountGlobalDialog as mountDependenciesSetupProgressIndicatorDialog } from '@renderer/features/DependenciesSetupProgressIndicatorDialog/operations'
|
||||
import { mountGlobalDialog as mountWaitForLoginDialog } from '@renderer/features/WaitForLoginDialog/operations'
|
||||
|
||||
const unmountedCbs: Array<InstanceType<typeof Function>> = []
|
||||
onUnmounted(() => {
|
||||
@@ -13,10 +14,31 @@ onUnmounted(() => {
|
||||
} catch {}
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
electron.ipcRenderer.on('check-boss-zhipin-cookie-file', mountWaitForLoginDialog)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
electron.ipcRenderer.removeListener('check-boss-zhipin-cookie-file', mountWaitForLoginDialog)
|
||||
})
|
||||
;(async () => {
|
||||
const checkDependenciesResult = await electron.ipcRenderer.invoke('check-dependencies')
|
||||
if (Object.values(checkDependenciesResult).includes(false)) {
|
||||
mountDependenciesSetupProgressIndicatorDialog(checkDependenciesResult)
|
||||
const processWaitee = Promise.withResolvers()
|
||||
mountDependenciesSetupProgressIndicatorDialog({
|
||||
checkDependenciesResult, processWaitee
|
||||
})
|
||||
|
||||
await processWaitee.promise
|
||||
}
|
||||
|
||||
const isCookieFileValid = await electron.ipcRenderer.invoke('check-boss-zhipin-cookie-file')
|
||||
if (!isCookieFileValid) {
|
||||
const processWaitee = Promise.withResolvers()
|
||||
mountWaitForLoginDialog({
|
||||
processWaitee
|
||||
})
|
||||
|
||||
await processWaitee.promise
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
html, body {
|
||||
--monospace-font-family: Monaco, Consolas, Menlo, monospace;
|
||||
font-family: var(--monospace-font-family);
|
||||
--monospace-font-family: Monaco, Consolas, Menlo;
|
||||
--sans-serif-font-family: 'PingFang SC', 'Microsoft Yahei', Helvetica, Arial;
|
||||
font-family: var(--monospace-font-family), var(--sans-serif-font-family);
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
25
packages/utils/puppeteer/block-navigation.mjs
Normal file
25
packages/utils/puppeteer/block-navigation.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
export async function blockNavigation(page, predictor = (url) => true) {
|
||||
console.log(`block navigation for puppeteer page from url ${page.url()}`)
|
||||
await page.setRequestInterception(true)
|
||||
|
||||
const handler = (req) => {
|
||||
if (req.isNavigationRequest() && req.frame() === page.mainFrame() && predictor(req)) {
|
||||
req.abort('aborted')
|
||||
} else {
|
||||
try {
|
||||
req.continue()
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page.on('request', handler)
|
||||
|
||||
return {
|
||||
dispose: async () => {
|
||||
page.off('request', handler)
|
||||
await page.setRequestInterception(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
18
packages/utils/puppeteer/local-storage.mjs
Normal file
18
packages/utils/puppeteer/local-storage.mjs
Normal file
@@ -0,0 +1,18 @@
|
||||
export const setDomainLocalStorage = async (browser, url, kv) => {
|
||||
const page = await browser.newPage();
|
||||
await page.setRequestInterception(true);
|
||||
page.on('request', r => {
|
||||
r.respond({
|
||||
status: 200,
|
||||
contentType: 'text/plain',
|
||||
body: ':)',
|
||||
});
|
||||
});
|
||||
await page.goto(url);
|
||||
await page.evaluate(kv => {
|
||||
Object.keys(kv).forEach(k => {
|
||||
localStorage.setItem(k, kv[k]);
|
||||
})
|
||||
}, kv);
|
||||
await page.close();
|
||||
};
|
||||
67
pnpm-lock.yaml
generated
67
pnpm-lock.yaml
generated
@@ -1,9 +1,5 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -35,6 +31,21 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../utils
|
||||
|
||||
packages/launch-bosszhipin-login-page-with-preload-extension:
|
||||
dependencies:
|
||||
'@geekgeekrun/geek-auto-start-chat-with-boss':
|
||||
specifier: workspace:*
|
||||
version: link:../geek-auto-start-chat-with-boss
|
||||
'@geekgeekrun/utils':
|
||||
specifier: workspace:*
|
||||
version: link:../utils
|
||||
extract-zip:
|
||||
specifier: ^2.0.1
|
||||
version: 2.0.1
|
||||
node-fetch:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
|
||||
packages/run-core-of-geek-auto-start-chat-with-boss:
|
||||
dependencies:
|
||||
'@geekgeekrun/dingtalk-plugin':
|
||||
@@ -61,6 +72,9 @@ importers:
|
||||
'@geekgeekrun/geek-auto-start-chat-with-boss':
|
||||
specifier: workspace:*
|
||||
version: link:../geek-auto-start-chat-with-boss
|
||||
'@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension':
|
||||
specifier: workspace:*
|
||||
version: link:../launch-bosszhipin-login-page-with-preload-extension
|
||||
'@geekgeekrun/utils':
|
||||
specifier: workspace:*
|
||||
version: link:../utils
|
||||
@@ -1271,7 +1285,7 @@ packages:
|
||||
/@types/fs-extra@9.0.13:
|
||||
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
|
||||
dependencies:
|
||||
'@types/node': 18.19.9
|
||||
'@types/node': 18.19.15
|
||||
dev: true
|
||||
|
||||
/@types/http-cache-semantics@4.0.4:
|
||||
@@ -2460,6 +2474,11 @@ packages:
|
||||
/csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
/data-uri-to-buffer@4.0.1:
|
||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||
engines: {node: '>= 12'}
|
||||
dev: false
|
||||
|
||||
/data-uri-to-buffer@6.0.1:
|
||||
resolution: {integrity: sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -3077,6 +3096,14 @@ packages:
|
||||
dependencies:
|
||||
pend: 1.2.0
|
||||
|
||||
/fetch-blob@3.2.0:
|
||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||
engines: {node: ^12.20 || >= 14.13}
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 3.3.3
|
||||
dev: false
|
||||
|
||||
/file-entry-cache@6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
@@ -3161,6 +3188,13 @@ packages:
|
||||
mime-types: 2.1.35
|
||||
dev: true
|
||||
|
||||
/formdata-polyfill@4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
dev: false
|
||||
|
||||
/fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: false
|
||||
@@ -4018,6 +4052,11 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
dev: false
|
||||
|
||||
/node-fetch-native@1.6.2:
|
||||
resolution: {integrity: sha512-69mtXOFZ6hSkYiXAVB5SqaRvrbITC/NPyqv7yuu/qw0nmgPyYbIMYYNIDhNtwPrzk0ptrimrLz/hhjvm4w5Z+w==}
|
||||
dev: true
|
||||
@@ -4034,6 +4073,15 @@ packages:
|
||||
whatwg-url: 5.0.0
|
||||
dev: false
|
||||
|
||||
/node-fetch@3.3.2:
|
||||
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dependencies:
|
||||
data-uri-to-buffer: 4.0.1
|
||||
fetch-blob: 3.2.0
|
||||
formdata-polyfill: 4.0.10
|
||||
dev: false
|
||||
|
||||
/node-releases@2.0.14:
|
||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||
dev: true
|
||||
@@ -5286,6 +5334,11 @@ packages:
|
||||
'@vue/shared': 3.4.15
|
||||
typescript: 5.3.3
|
||||
|
||||
/web-streams-polyfill@3.3.3:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
dev: false
|
||||
|
||||
/webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
dev: false
|
||||
@@ -5408,3 +5461,7 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
Reference in New Issue
Block a user