Created
February 10, 2022 19:45
-
-
Save iinfin/e947ac60eef6de5598a6fb7ffdb9f977 to your computer and use it in GitHub Desktop.
cloudflare password protection per site using values from KV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const _REALM = 'Secure Area'; | |
| const _DEFAULT_USERNAME = 'username'; | |
| const _DEFAULT_PASSWORD = null; | |
| addEventListener('fetch', (event) => { | |
| event.respondWith(handleRequest(event.request)); | |
| }); | |
| async function handleRequest(request) { | |
| const password = await getValidCredentials(request); | |
| return createResponse(request, password); | |
| } | |
| // ################################################################################################# | |
| /** | |
| * Get password from Cloudflare KV | |
| * project-name from url to be used as key | |
| * https://developers.cloudflare.com/workers/runtime-apis/kv#reading-key-value-pairs | |
| * @returns {string} | |
| */ | |
| async function getValidCredentials(request) { | |
| const name = new URL(request.url).host.split('.')[0]; | |
| const password = await SECURE.get(name); | |
| return password || _DEFAULT_PASSWORD; | |
| } | |
| // ################################################################################################# | |
| /** | |
| * Either accept or deny access, create Response | |
| * @param {Request} request | |
| * @param {string} password | |
| * @returns {Response} | |
| */ | |
| async function createResponse(request, password) { | |
| if (password === null) { | |
| // password is not set | |
| const response = await fetch(request); | |
| return response; | |
| } else { | |
| // security check | |
| const authorization = request.headers.get('authorization'); | |
| if (!request.headers.has('authorization')) { | |
| return getUnauthorizedResponse('Provide User Name and Password to access this page.'); | |
| } | |
| const credentials = parseCredentials(authorization); | |
| if (credentials[0] !== _DEFAULT_USERNAME || credentials[1] !== password) { | |
| return getUnauthorizedResponse('The User Name and Password combination you have entered is invalid.'); | |
| } | |
| const response = await fetch(request); | |
| return response; | |
| } | |
| } | |
| // ################################################################################################# | |
| /** | |
| * Break down base64 encoded authorization string into plain-text username and password | |
| * @param {string} authorization | |
| * @returns {string[]} | |
| */ | |
| function parseCredentials(authorization) { | |
| const parts = authorization.split(' '); | |
| const plainAuth = atob(parts[1]); | |
| const credentials = plainAuth.split(':'); | |
| return credentials; | |
| } | |
| /** | |
| * Helper funtion to generate Response object | |
| * @param {string} message | |
| * @returns {Response} | |
| */ | |
| function getUnauthorizedResponse(message) { | |
| let response = new Response(message, { | |
| status: 401, | |
| }); | |
| response.headers.set('WWW-Authenticate', `Basic realm="${_REALM}"`); | |
| return response; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment