cloudflared
Advanced tools
Comparing version 0.2.0 to 0.2.1
@@ -39,2 +39,3 @@ import { ChildProcess } from 'node:child_process'; | ||
* Cloudflared launchd identifier. | ||
* @platform macOS | ||
*/ | ||
@@ -44,7 +45,8 @@ declare const identifier = "com.cloudflare.cloudflared"; | ||
* Path of service related files. | ||
* @platform macOS | ||
*/ | ||
declare const MACOS_SERVICE_PATH: { | ||
PLIST: string; | ||
OUT: string; | ||
ERR: string; | ||
readonly PLIST: string; | ||
readonly OUT: string; | ||
readonly ERR: string; | ||
}; | ||
@@ -62,2 +64,3 @@ /** | ||
clean: typeof clean; | ||
journal: typeof journal; | ||
}; | ||
@@ -79,2 +82,3 @@ /** | ||
* @param token Tunnel service token. | ||
* @platform macOS, linux | ||
*/ | ||
@@ -84,2 +88,3 @@ declare function install(token?: string): void; | ||
* Uninstall Cloudflared service. | ||
* @platform macOS, linux | ||
*/ | ||
@@ -90,2 +95,3 @@ declare function uninstall(): void; | ||
* @returns stdout log of cloudflared service. | ||
* @platform macOS, linux (sysv) | ||
*/ | ||
@@ -96,7 +102,16 @@ declare function log(): string; | ||
* @returns stderr log of cloudflared service. | ||
* @platform macOS, linux (sysv) | ||
*/ | ||
declare function err(): string; | ||
/** | ||
* Get cloudflared service journal from journalctl. | ||
* @param n The number of entries to return. | ||
* @returns cloudflared service journal. | ||
* @platform linux (systemd) | ||
*/ | ||
declare function journal(n?: number): string; | ||
/** | ||
* Get informations of current running cloudflared service. | ||
* @returns informations of current running cloudflared service. | ||
* @platform macOS, linux | ||
*/ | ||
@@ -114,3 +129,3 @@ declare function current(): { | ||
config: { | ||
ingress: { | ||
ingress?: { | ||
service: string; | ||
@@ -124,2 +139,3 @@ hostname?: string; | ||
* Clean up service log files. | ||
* @platform macOS | ||
*/ | ||
@@ -130,2 +146,3 @@ declare function clean(): void; | ||
* @returns true if service is installed, false otherwise. | ||
* @platform macOS, linux | ||
*/ | ||
@@ -132,0 +149,0 @@ declare function exists(): boolean; |
@@ -6,2 +6,3 @@ import os from "node:os"; | ||
const identifier = "com.cloudflare.cloudflared"; | ||
const service_name = "cloudflared.service"; | ||
const MACOS_SERVICE_PATH = { | ||
@@ -12,3 +13,9 @@ PLIST: is_root() ? `/Library/LaunchDaemons/${identifier}.plist` : `${os.homedir()}/Library/LaunchAgents/${identifier}.plist`, | ||
}; | ||
const service = { install, uninstall, exists, log, err, current, clean }; | ||
const LINUX_SERVICE_PATH = { | ||
SYSTEMD: `/etc/systemd/system/${service_name}`, | ||
SERVICE: "/etc/init.d/cloudflared", | ||
SERVICE_OUT: "/var/log/cloudflared.log", | ||
SERVICE_ERR: "/var/log/cloudflared.err" | ||
}; | ||
const service = { install, uninstall, exists, log, err, current, clean, journal }; | ||
class AlreadyInstalledError extends Error { | ||
@@ -25,3 +32,3 @@ constructor() { | ||
function install(token) { | ||
if (process.platform !== "darwin") { | ||
if (!["darwin", "linux"].includes(process.platform)) { | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
@@ -36,6 +43,9 @@ } | ||
} | ||
spawnSync(bin, args); | ||
const result = spawnSync(bin, args); | ||
if (result.status !== 0) { | ||
throw new Error(`service install failed: ${result.stderr.toString()}`); | ||
} | ||
} | ||
function uninstall() { | ||
if (process.platform !== "darwin") { | ||
if (!["darwin", "linux"].includes(process.platform)) { | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
@@ -46,27 +56,48 @@ } | ||
} | ||
spawnSync(bin, ["service", "uninstall"]); | ||
fs.rmSync(MACOS_SERVICE_PATH.OUT); | ||
fs.rmSync(MACOS_SERVICE_PATH.ERR); | ||
const result = spawnSync(bin, ["service", "uninstall"]); | ||
if (result.status !== 0) { | ||
throw new Error(`service uninstall failed: ${result.stderr.toString()}`); | ||
} | ||
if (process.platform === "darwin") { | ||
fs.rmSync(MACOS_SERVICE_PATH.OUT); | ||
fs.rmSync(MACOS_SERVICE_PATH.ERR); | ||
} else if (process.platform === "linux" && !is_systemd()) { | ||
fs.rmSync(LINUX_SERVICE_PATH.SERVICE_OUT); | ||
fs.rmSync(LINUX_SERVICE_PATH.SERVICE_ERR); | ||
} | ||
} | ||
function log() { | ||
if (process.platform !== "darwin") { | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
} | ||
if (!exists()) { | ||
throw new NotInstalledError(); | ||
} | ||
return fs.readFileSync(MACOS_SERVICE_PATH.OUT, "utf8"); | ||
if (process.platform === "darwin") { | ||
return fs.readFileSync(MACOS_SERVICE_PATH.OUT, "utf8"); | ||
} | ||
if (process.platform === "linux" && !is_systemd()) { | ||
return fs.readFileSync(LINUX_SERVICE_PATH.SERVICE_OUT, "utf8"); | ||
} | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
} | ||
function err() { | ||
if (process.platform !== "darwin") { | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
} | ||
if (!exists()) { | ||
throw new NotInstalledError(); | ||
} | ||
return fs.readFileSync(MACOS_SERVICE_PATH.ERR, "utf8"); | ||
if (process.platform === "darwin") { | ||
return fs.readFileSync(MACOS_SERVICE_PATH.ERR, "utf8"); | ||
} | ||
if (process.platform === "linux" && !is_systemd()) { | ||
return fs.readFileSync(LINUX_SERVICE_PATH.SERVICE_ERR, "utf8"); | ||
} | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
} | ||
function journal(n = 300) { | ||
if (process.platform === "linux" && is_systemd()) { | ||
const args = ["-u", service_name, "-o", "cat", "-n", n.toString()]; | ||
return spawnSync("journalctl", args).stdout.toString(); | ||
} | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
} | ||
function current() { | ||
var _a, _b, _c; | ||
if (process.platform !== "darwin") { | ||
var _a, _b, _c, _d; | ||
if (!["darwin", "linux"].includes(process.platform)) { | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
@@ -77,36 +108,44 @@ } | ||
} | ||
const error = err(); | ||
const log2 = is_systemd() ? journal() : err(); | ||
const regex = { | ||
tunnelID: /tunnelID=([0-9a-z-]+)/g, | ||
connectorID: /Connector ID: ([0-9a-z-]+)/g, | ||
connections: /Connection ([a-z0-9-]+) registered connIndex=(\d) ip=([0-9.]+) location=([A-Z]+)/g, | ||
metrics: /metrics server on ([0-9.:]+\/metrics)/g, | ||
config: /config="(.+[^\\])"/g | ||
tunnelID: /tunnelID=([0-9a-z-]+)/, | ||
connectorID: /Connector ID: ([0-9a-z-]+)/, | ||
connect: /Connection ([a-z0-9-]+) registered connIndex=(\d) ip=([0-9.]+) location=([A-Z]+)/, | ||
disconnect: /Unregistered tunnel connection connIndex=(\d)/, | ||
metrics: /metrics server on ([0-9.:]+\/metrics)/, | ||
config: /config="(.+[^\\])"/ | ||
}; | ||
const match = { | ||
tunnelID: regex.tunnelID.exec(error), | ||
connectorID: regex.connectorID.exec(error), | ||
connections: error.matchAll(regex.connections), | ||
metrics: regex.metrics.exec(error), | ||
config: regex.config.exec(error) | ||
}; | ||
const config = (() => { | ||
var _a2; | ||
let tunnelID = ""; | ||
let connectorID = ""; | ||
const connections = []; | ||
let metrics = ""; | ||
let config = {}; | ||
for (const line of log2.split("\n")) { | ||
try { | ||
return JSON.parse(((_a2 = match.config) == null ? void 0 : _a2[1].replace(/\\/g, "")) ?? "{}"); | ||
} catch (e) { | ||
return {}; | ||
if (line.match(regex.tunnelID)) { | ||
tunnelID = ((_a = line.match(regex.tunnelID)) == null ? void 0 : _a[1]) ?? ""; | ||
} else if (line.match(regex.connectorID)) { | ||
connectorID = ((_b = line.match(regex.connectorID)) == null ? void 0 : _b[1]) ?? ""; | ||
} else if (line.match(regex.connect)) { | ||
const [, id, idx, ip, location] = line.match(regex.connect) ?? []; | ||
if (id && idx && ip && location) { | ||
connections[parseInt(idx)] = { id, ip, location }; | ||
} | ||
} else if (line.match(regex.disconnect)) { | ||
const [, idx] = line.match(regex.disconnect) ?? []; | ||
if (parseInt(idx) in connections) { | ||
connections[parseInt(idx)] = { id: "", ip: "", location: "" }; | ||
} | ||
} else if (line.match(regex.metrics)) { | ||
metrics = ((_c = line.match(regex.metrics)) == null ? void 0 : _c[1]) ?? ""; | ||
} else if (line.match(regex.config)) { | ||
config = JSON.parse(((_d = line.match(regex.config)) == null ? void 0 : _d[1].replace(/\\/g, "")) ?? "{}"); | ||
} | ||
} catch (err2) { | ||
if (process.env.VERBOSE) { | ||
console.error("log parsing failed", err2); | ||
} | ||
} | ||
})(); | ||
return { | ||
tunnelID: ((_a = match.tunnelID) == null ? void 0 : _a[1]) ?? "", | ||
connectorID: ((_b = match.connectorID) == null ? void 0 : _b[1]) ?? "", | ||
connections: [...match.connections].map(([, id, , ip, location]) => ({ | ||
id, | ||
ip, | ||
location | ||
})) ?? [], | ||
metrics: ((_c = match.metrics) == null ? void 0 : _c[1]) ?? "", | ||
config | ||
}; | ||
} | ||
return { tunnelID, connectorID, connections, metrics, config }; | ||
} | ||
@@ -124,3 +163,8 @@ function clean() { | ||
function exists() { | ||
return is_root() ? fs.existsSync(MACOS_SERVICE_PATH.PLIST) : fs.existsSync(MACOS_SERVICE_PATH.PLIST); | ||
if (process.platform === "darwin") { | ||
return fs.existsSync(MACOS_SERVICE_PATH.PLIST); | ||
} else if (process.platform === "linux") { | ||
return is_systemd() ? fs.existsSync(LINUX_SERVICE_PATH.SYSTEMD) : fs.existsSync(LINUX_SERVICE_PATH.SERVICE); | ||
} | ||
throw new Error(`Not Implemented on platform ${process.platform}`); | ||
} | ||
@@ -131,4 +175,8 @@ function is_root() { | ||
} | ||
function is_systemd() { | ||
return process.platform === "linux" && fs.existsSync("/run/systemd/system"); | ||
} | ||
export { | ||
AlreadyInstalledError, | ||
LINUX_SERVICE_PATH, | ||
MACOS_SERVICE_PATH, | ||
@@ -142,5 +190,7 @@ NotInstalledError, | ||
install, | ||
journal, | ||
log, | ||
service, | ||
service_name, | ||
uninstall | ||
}; |
{ | ||
"name": "cloudflared", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Cloudflared in Node.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -159,1 +159,5 @@ # cloudflared | ||
``` | ||
NOTICE: On linux, service can only be installed and uninstalled by root. | ||
Run service test on linux: `sudo -E env "PATH=$PATH" pnpm test` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
45712
1106
163
0
10