1import { certificateFor } from '@expo/devcert';
2import chalk from 'chalk';
3import fs from 'fs/promises';
4import path from 'path';
5
6import * as Log from '../../../log';
7import { ensureDirectoryAsync } from '../../../utils/dir';
8import { ensureDotExpoProjectDirectoryInitialized } from '../../project/dotExpo';
9
10// TODO: Move to doctor as a prereq.
11
12/** Ensure TLS is setup and environment variables are set. */
13export async function ensureEnvironmentSupportsTLSAsync(projectRoot: string) {
14  if (!process.env.SSL_CRT_FILE || !process.env.SSL_KEY_FILE) {
15    const tls = await getTLSCertAsync(projectRoot);
16    if (tls) {
17      process.env.SSL_CRT_FILE = tls.certPath;
18      process.env.SSL_KEY_FILE = tls.keyPath;
19    }
20  }
21}
22
23/** Create TLS and write to files in the temporary directory. Exposed for testing. */
24export async function getTLSCertAsync(
25  projectRoot: string
26): Promise<{ keyPath: string; certPath: string } | false> {
27  Log.log(
28    chalk`Creating TLS certificate for localhost. {dim This functionality may not work on all computers.}`
29  );
30
31  const name = 'localhost';
32  const result = await certificateFor(name);
33  if (result) {
34    const dotExpoDir = ensureDotExpoProjectDirectoryInitialized(projectRoot);
35
36    const { key, cert } = result;
37    const folder = path.join(dotExpoDir, 'tls');
38    const keyPath = path.join(folder, `key-${name}.pem`);
39    const certPath = path.join(folder, `cert-${name}.pem`);
40
41    await ensureDirectoryAsync(folder);
42    await Promise.allSettled([fs.writeFile(keyPath, key), fs.writeFile(certPath, cert)]);
43
44    return {
45      keyPath,
46      certPath,
47    };
48  }
49  return result;
50}
51