diff --git a/.env b/.env index fef817a..7d6cd09 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ DUMMY_HTML_DIR=./development-test-data-dir/ +ASSETS_DOMAIN=assets.suyono.me diff --git a/app/mark/page.tsx b/app/mark/page.tsx index d19163d..9962de4 100644 --- a/app/mark/page.tsx +++ b/app/mark/page.tsx @@ -2,7 +2,7 @@ import { unified } from 'unified'; import remarkGfm from 'remark-gfm'; import remarkParse from 'remark-parse'; import remarkRehype, { Options as RemarkRehypeOptions } from 'remark-rehype'; -import rehypeSanitize from 'rehype-sanitize'; +import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; import rehypeHighlight, { Options as RehypeHighlightOptions } from 'rehype-highlight'; import rehypeReact, { Options as RehypeReactOptions } from 'rehype-react'; import { all } from 'lowlight'; @@ -10,33 +10,112 @@ import { Fragment, jsx, jsxs } from 'react/jsx-runtime'; import { MarkPostString } from '@/components/dummyPost'; import { raleway, roboto, nunito } from "@/app/fonts"; import rehypeRaw from "rehype-raw"; +import Image from "next/image"; export default async function Mark() { let content = await MarkPostString(); let result = await unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkRehype, { allowDangerousHtml: true } as RemarkRehypeOptions) - .use(rehypeRaw) - .use(rehypeSanitize) - .use(rehypeHighlight, { - languages: all, - } as RehypeHighlightOptions) - .use(rehypeReact, { - Fragment: Fragment, - jsx: jsx, - jsxs: jsxs, - components: { - h1: props =>

{props.children}

, - h2: props =>

{props.children}

, - h3: props =>

{props.children}

, - h4: props =>

{props.children}

, - p: props =>

{props.children}

, - pre: props =>
{props.children}
, - hr: props =>
+ .use(remarkParse) + .use(remarkGfm) + .use(remarkRehype, { allowDangerousHtml: true } as RemarkRehypeOptions) + .use(rehypeRaw) + .use(rehypeSanitize, { + ...defaultSchema, + tagNames: [ + ...(defaultSchema.tagNames || []), + 'figure', + 'figcaption', + ] + }) + .use(rehypeHighlight, { + languages: all, + } as RehypeHighlightOptions) + .use(rehypeReact, { + Fragment: Fragment, + jsx: jsx, + jsxs: jsxs, + passNode: true, + components: { + h1: (props) => ( +

+ {props.children} +

+ ), + h2: (props) => ( +

+ {props.children} +

+ ), + h3: (props) => ( +

+ {props.children} +

+ ), + h4: (props) => ( +

+ {props.children} +

+ ), + p: (props) => ( +

+ {props.children} +

+ ), + pre: (props) => ( +
+
{props.children}
+
+ ), + hr: (props) =>
, + img: (props) => { + let src: string = ""; + let alt: string = ""; + + if (typeof props.src === "undefined") { + src = `https://${process.env.ASSETS_DOMAIN}/broken-image.svg`; + } else { + src = props.src; } - } as RehypeReactOptions) - .process(content); + + if (typeof props.alt === "string") { + alt = props.alt; + } + + if ( + typeof props.width === "undefined" || + typeof props.height === "undefined" + ) { + return ( + {alt} + ); + } else { + return ( + {alt} + ); + } + }, + figcaption: (props) => ( +
+ {props.children} +
+ ), + }, + } as RehypeReactOptions) + .process(content); return result.result; } \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 9a07496..5772c98 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -7,7 +7,7 @@ export default function Home() {
{`blog post thumbnail +MacOS Keychain Access +
MacOS Keychain Access Window, accessible from settings page
+ + +On Mac, it is called Keychain Access. To add a certificate, drag the pfx file onto Keychain Access. You'll need to +input the exact export password when you convert the crt file to pfx/p12 format. + +When you click Manage device certificate from the browser setting page, this window will open on Windows. You can import +the pfx file using this window. + +
+Windows certificate dialog +
Certificates dialog on Widows, open from chrome settings page
+
+ +Alternatively, you can use the certmgr to import the certificate. You can open it from the Windows setting or Control Panel. + +
+Windows certificates manager +
Windows certificates manager, accessible from Control Panel
+
+ +### Mozilla Firefox + +Firefox has its own Certificate Manager dialog. You can import and manage the certificate from it. It also connects to +the operating system certificate management. + +
+Firefox certificates manager +
Mozilla Firefox Certificate Manager
+
+ +--- + +## Testing + +You can use any browser or tool, like cURL, to test the client certificate verification setup. If your client +certificate verification succeeds, you can open the page using a browser. If your browser shows something like +403 Forbidden, it means either your browser does not have the certificate or something wrong in your setup. + +### cURL + +Without a valid client certificate + +```sh +curl -v https://www.example.com/ +``` + +response + +``` +> GET / HTTP/2 +> Host: www.example.com +> user-agent: curl/7.74.0 +> accept: */* +> +< HTTP/2 403 +< server: nginx +< date: Wed, 12 Jul 2023 04:54:02 GMT +< content-type: text/html +< content-length: 146 +< + +403 Forbidden + +

403 Forbidden

+
nginx
+ + +``` + +With a valid client certificate + +```sh +curl --cert user.crt --key user.key -v https://www.example.com/ +``` + +response + +``` +> GET / HTTP/2 +> Host: www.example.com +> user-agent: curl/7.74.0 +> accept: */* +> +< HTTP/2 200 +< server: nginx +. +. +. +snipped +``` + +--- + +## Revoking Access + +This setup recognizes users by the certificate they are using. Revoking access here means revoking the users' +certificates. We can achieve this by leveraging OpenSSL's CRL feature. To use it, we need to have the CA database. +I explained how to set it up in the section above. + +### Revoke client certificate + +```sh +openssl ca -config ca.cnf -revoke user.crt +``` + +### Generate CRL file + +```sh +openssl ca -config ca.cnf -gencrl -out crl.pem +``` + +### Verifying CRL file + +```sh +openssl crl -in crl.pem -noout -text +``` + +### Nginx configuration for CRL + +You need to add the `ssl_crl` directive in the Nginx configuration file, as shown in the example below. + +```nginx + .... + ssl_client_certificate /path/to/client/verification/ca.crt; + ssl_verify_client optional; + ssl_verify_depth 2; + ssl_crl /path/to/crl.pem; # configure nginx to read the crl file + + + root /usr/share/nginx/html; + .... +``` +