Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.x] Auto detect Valet / Herd TLS certificates #180

Merged
merged 7 commits into from
Dec 15, 2023
Merged
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
96 changes: 70 additions & 26 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,17 @@ interface PluginConfig {
/**
* Utilise the Herd or Valet TLS certificates.
*
* @default false
* @default null
*/
detectTls?: string|boolean,
detectTls?: string|boolean|null,

/**
* Utilise the Herd or Valet TLS certificates.
*
* @default false
* @default null
* @deprecated use "detectTls" instead
*/
valetTls?: string|boolean,
valetTls?: string|boolean|null,

/**
* Transform the code while serving.
Expand Down Expand Up @@ -211,6 +211,16 @@ function resolveLaravelPlugin(pluginConfig: Required<PluginConfig>): LaravelPlug
server.config.logger.info(`\n ${colors.red(`${colors.bold('LARAVEL')} ${laravelVersion()}`)} ${colors.dim('plugin')} ${colors.bold(`v${pluginVersion()}`)}`)
server.config.logger.info('')
server.config.logger.info(` ${colors.green('➜')} ${colors.bold('APP_URL')}: ${colors.cyan(appUrl.replace(/:(\d+)/, (_, port) => `:${colors.bold(port)}`))}`)

if (typeof resolvedConfig.server.https === 'object' && typeof resolvedConfig.server.https.key === 'string') {
if (resolvedConfig.server.https.key.startsWith(herdConfigPath())) {
server.config.logger.info(` ${colors.green('➜')} Using Herd certificate to secure Vite.`)
}

if (resolvedConfig.server.https.key.startsWith(valetConfigPath())) {
server.config.logger.info(` ${colors.green('➜')} Using Valet certificate to secure Vite.`)
}
}
}, 100)
}
})
Expand Down Expand Up @@ -342,8 +352,8 @@ function resolvePluginConfig(config: string|string[]|PluginConfig): Required<Plu
ssrOutputDirectory: config.ssrOutputDirectory ?? 'bootstrap/ssr',
refresh: config.refresh ?? false,
hotFile: config.hotFile ?? path.join((config.publicDirectory ?? 'public'), 'hot'),
valetTls: config.valetTls ?? false,
detectTls: config.detectTls ?? config.valetTls ?? false,
valetTls: config.valetTls ?? null,
detectTls: config.detectTls ?? config.valetTls ?? null,
transformOnServe: config.transformOnServe ?? ((code) => code),
}
}
Expand Down Expand Up @@ -507,62 +517,82 @@ function resolveHostFromEnv(env: Record<string, string>): string|undefined
/**
* Resolve the Herd or Valet server config for the given host.
*/
function resolveDevelopmentEnvironmentServerConfig(host: string|boolean): {
function resolveDevelopmentEnvironmentServerConfig(host: string|boolean|null): {
hmr?: { host: string }
host?: string,
https?: { cert: Buffer, key: Buffer }
https?: { cert: string, key: string }
}|undefined {
if (host === false) {
return
}

const configPath = determineDevelopmentEnvironmentConfigPath();

host = host === true ? resolveDevelopmentEnvironmentHost(configPath) : host
if (typeof configPath === 'undefined' && host === null) {
return
}

if (typeof configPath === 'undefined') {
throw Error(`Unable to find the Herd or Valet configuration directory. Please check they are correctly installed.`)
}

const keyPath = path.resolve(configPath, 'Certificates', `${host}.key`)
const certPath = path.resolve(configPath, 'Certificates', `${host}.crt`)
const resolvedHost = host === true || host === null
? path.basename(process.cwd()) + '.' + resolveDevelopmentEnvironmentTld(configPath)
: host

const keyPath = path.resolve(configPath, 'Certificates', `${resolvedHost}.key`)
const certPath = path.resolve(configPath, 'Certificates', `${resolvedHost}.crt`)

if (! fs.existsSync(keyPath) || ! fs.existsSync(certPath)) {
throw Error(`Unable to find certificate files for your host [${host}] in the [${configPath}/Certificates] directory. Ensure you have secured the site via the Herd UI or run \`valet secure\`.`)
if (host === null) {
return
}

if (configPath === herdConfigPath()) {
throw Error(`Unable to find certificate files for your host [${resolvedHost}] in the [${configPath}/Certificates] directory. Ensure you have secured the site via the Herd UI.`)
} else if (typeof host === 'string') {
throw Error(`Unable to find certificate files for your host [${resolvedHost}] in the [${configPath}/Certificates] directory. Ensure you have secured the site by running \`valet secure ${host}\`.`)
} else {
throw Error(`Unable to find certificate files for your host [${resolvedHost}] in the [${configPath}/Certificates] directory. Ensure you have secured the site by running \`valet secure\`.`)
}
}

return {
hmr: { host },
host,
hmr: { host: resolvedHost },
host: resolvedHost,
https: {
key: fs.readFileSync(keyPath),
cert: fs.readFileSync(certPath),
key: keyPath,
cert: certPath,
},
}
}

/**
* Resolve the path to the Herd or Valet configuration directory.
*/
function determineDevelopmentEnvironmentConfigPath(): string {
const herdConfigPath = path.resolve(os.homedir(), 'Library', 'Application Support', 'Herd', 'config', 'valet')

if (fs.existsSync(herdConfigPath)) {
return herdConfigPath
function determineDevelopmentEnvironmentConfigPath(): string|undefined {
if (fs.existsSync(herdConfigPath())) {
return herdConfigPath()
}

return path.resolve(os.homedir(), '.config', 'valet');
if (fs.existsSync(valetConfigPath())) {
return valetConfigPath()
}
}

/**
* Resolve the Herd or Valet host for the current directory.
* Resolve the TLD via the config path.
*/
function resolveDevelopmentEnvironmentHost(configPath: string): string {
function resolveDevelopmentEnvironmentTld(configPath: string): string {
const configFile = path.resolve(configPath, 'config.json')

if (! fs.existsSync(configFile)) {
throw Error(`Unable to find the configuration file [${configFile}]. You will need to manually specify the host in the \`detectTls\` configuration option.`)
throw Error(`Unable to find the configuration file [${configFile}].`)
}

const config: { tld: string } = JSON.parse(fs.readFileSync(configFile, 'utf-8'))

return path.basename(process.cwd()) + '.' + config.tld
return config.tld
}

/**
Expand All @@ -571,3 +601,17 @@ function resolveDevelopmentEnvironmentHost(configPath: string): string {
function dirname(): string {
return fileURLToPath(new URL('.', import.meta.url))
}

/**
* Herd's configuration directory.
*/
function herdConfigPath(): string {
return path.resolve(os.homedir(), 'Library', 'Application Support', 'Herd', 'config', 'valet')
}

/**
* Valet's configuration directory.
*/
function valetConfigPath(): string {
return path.resolve(os.homedir(), '.config', 'valet')
}