Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/vite/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export default defineConfig({
plugins: [
Inspect(),
Unplugin({
target: 'test.abc.com',
target: 'test23.abc.com',
showCaddyLog: true,
enable: true,
https: false,
}),
],
})
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,15 @@
"dependencies": {
"consola": "^3.2.3",
"dotenv-flow": "^4.1.0",
"easy-host-cli": "^1.0.10",
"got-cjs": "^12.5.4",
"hosts-so-easy": "^1.2.9",
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.4",
"kill-port": "^2.0.1",
"ora": "5",
"picocolors": "^1.0.0",
"sudo-prompt": "^9.2.1",
"tsx": "^4.7.1",
"unplugin": "^1.7.1"
},
Expand Down
31 changes: 23 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 39 additions & 44 deletions src/caddy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { got } from 'got-cjs'
import { HttpProxyAgent } from 'http-proxy-agent'
import { HttpsProxyAgent } from 'https-proxy-agent'
import kill from 'kill-port'
import { chmodRecursive, consola, once } from '../utils'
import { addHost, removeHost } from '../host'
import { consola, once, runAsAdmin } from '../utils'
import { addHost, removeHost } from '../host/cli'
import { TEMP_DIR, caddyPath, supportList } from './constants'
import { logProgress, logProgressOver, tryPort } from './utils'

Expand All @@ -20,7 +20,7 @@ export async function download() {

if (!existsSync(TEMP_DIR)) {
mkdirSync(TEMP_DIR, { recursive: true })
chmodSync(TEMP_DIR, 0o777)
chmodSync(TEMP_DIR, 0o744)
}

const file = createWriteStream(caddyPath)
Expand All @@ -46,10 +46,9 @@ export async function download() {

const httpAgent = httpProxy ? new HttpProxyAgent(httpProxy) : undefined
const httpsAgent = httpsProxy ? new HttpsProxyAgent(httpsProxy) : undefined

const chmodCaddyOnce = once(() => {
// chmod +x
chmodSync(caddyPath, 0o777)
chmodSync(caddyPath, 0o744)
})

got.stream(dowmloadLink, {
Expand All @@ -65,7 +64,7 @@ export async function download() {
if (process.platform === 'win32')
return resolve(caddyPath)
// chmod +x
chmodSync(caddyPath, 0o777)
chmodSync(caddyPath, 0o744)
resolve(caddyPath)
}).on('error', (err) => {
// consola.error(err)
Expand All @@ -78,8 +77,8 @@ function testCaddy() {
return new Promise((resolve, reject) => {
if (!existsSync(caddyPath))
return resolve(false)
chmodSync(caddyPath, 0o777)
const child = process.platform === 'win32' ? spawn(caddyPath, []) : spawn('sudo', ['-E', caddyPath])
chmodSync(caddyPath, 0o744)
const child = spawn(caddyPath, [])
child.on('close', () => {
return resolve(false)
})
Expand Down Expand Up @@ -142,12 +141,37 @@ export class CaddyInstant {

return new Promise<void>((resolve, reject) => {
// caddy reverse-proxy --from target --to source --internal-certs
const child = process.platform !== 'win32'
? spawn('sudo', ['-E', caddyPath, 'reverse-proxy', '--from', `${target.split(':')[0]}${https ? '' : ':80'}`, '--to', `${source}`, '--internal-certs', '--insecure', '--disable-redirects'])
: spawn(caddyPath, ['reverse-proxy', '--from', `${target.split(':')[0]}`, '--to', `${source}`, '--internal-certs'])

child.on('error', (err) => {
return reject(err)
runAsAdmin([caddyPath,
'reverse-proxy',
'--from',
`${target.split(':')[0]}${https ? '' : ':80'}`,
'--to',
`${source}`,
'--internal-certs',
'--insecure',
'--disable-redirects',
].join(' '), 'caddy', (error, stdout, stderr) => {
if (error)
return reject(error)

// stderr.on('data', (data: any) => {
// const lines = (data.toString() as string).split('\n').map(line => line.trim())
// for (const line of lines) {
// // caddy log
// // eslint-disable-next-line no-console
// showCaddyLog && line && console.info(line)
// if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
// consola.error(line)
// // child.kill()
// return reject(line)
// }
// }
// })

// stdout.on('data', (_data: any) => {
// consola.info(_data.toString())
// resolve()
// })
})

process.on('SIGINT', async () => {
Expand Down Expand Up @@ -181,18 +205,6 @@ export class CaddyInstant {
if (!Number.isNaN(port) && await tryPort(port))
await kill(port, 'tcp')

// fix `Error: EPERM: operation not permitted`
const pwd = process.cwd()
const viteCacheDir = `${pwd}/node_modules/.vite`
if (existsSync(viteCacheDir))
chmodRecursive(viteCacheDir, 0o777)
const nuxtCacheDir = `${pwd}/.nuxt`
if (existsSync(nuxtCacheDir))
await chmodRecursive(nuxtCacheDir, 0o777)
const webpackCacheDir = `${pwd}/node_modules/.cache`
if (existsSync(webpackCacheDir))
chmodRecursive(webpackCacheDir, 0o777)

if (!restore || this.stoped)
return originalExit(code)

Expand All @@ -215,24 +227,7 @@ export class CaddyInstant {
}
}

child.stderr.on('data', (data) => {
const lines = (data.toString() as string).split('\n').map(line => line.trim())
for (const line of lines) {
// caddy log
// eslint-disable-next-line no-console
showCaddyLog && line && console.info(line)
if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
consola.error(line)
// child.kill()
return reject(line)
}
}
})

child.stdout.on('data', (_data) => {
consola.info(_data.toString())
resolve()
})
resolve()
})
}
}
9 changes: 9 additions & 0 deletions src/host/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { runAsAdmin } from '../utils'

export async function addHost(ip: string, host: string) {
return runAsAdmin(`npx easy-host-cli add --ip ${ip} --host ${host}`, 'addHost')
}

export async function removeHost(ip: string, host: string) {
return runAsAdmin(`npx easy-host-cli rm --ip ${ip} --host ${host}`, 'removeHost')
}
4 changes: 0 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ export const unpluginFactory: UnpluginFactory<Options> = options => ({
if (!enable)
return

if (!isAdmin()) {
consola.warn('please run as administrator')
return
}
if (!target) {
consola.fail('please provide target')
return
Expand Down
28 changes: 28 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import process from 'node:process'
import path from 'node:path'
import { chmod, readdir, stat } from 'node:fs/promises'
import { execSync } from 'node:child_process'
import { createConsola } from 'consola'

// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
const sudo = require('sudo-prompt')

export const consola = createConsola({
level: 3,
}).withTag('reverse-proxy')
Expand Down Expand Up @@ -41,3 +45,27 @@ export function isAdmin() {
return process.getuid && process.getuid() === 0
}
}

export function runAsAdmin(command: string, name?: string, fn?: (error: any, stdout: any, stderr: any) => void) {
return new Promise<boolean>((resolve, reject) => {
consola.log('exec command: ', command)
sudo.exec(command, {
name: `unpluginHttpsReverseProxy ${name}`,
}, (error: any, stdout: any, stderr: any) => {
try {
fn?.(error, stdout, stderr)
}
finally {
if (error) {
consola.error(error)
// eslint-disable-next-line prefer-promise-reject-errors
reject(false)
// eslint-disable-next-line no-unsafe-finally
return
}
consola.success(stdout)
resolve(true)
}
})
})
}