-
-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Neko Ayaka <neko@ayaka.moe>
- Loading branch information
1 parent
47ab3a5
commit 8df6e1f
Showing
12 changed files
with
356 additions
and
35 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<script setup lang="ts"> | ||
import { onMounted, ref } from 'vue' | ||
import { LazyHydrationWrapper } from 'vue3-lazy-hydration' | ||
import { decryptText, encryptText } from '../composables/crypto' | ||
const password = ref('') | ||
const iv = ref('') | ||
const errored = ref(false) | ||
const rawContent = '<div>a</div>' | ||
const encryptedHtml = ref('') | ||
const decryptedHtml = ref('') | ||
const trigger = ref(false) | ||
onMounted(async () => { | ||
try { | ||
const key = 'password' | ||
const encrypted = await encryptText(rawContent, key) | ||
encryptedHtml.value = encrypted.encryptedText | ||
iv.value = encrypted.ivBase64 | ||
} | ||
catch (err) { | ||
console.error('Failed to encrypt the content.') | ||
} | ||
}) | ||
async function onPasswordInput() { | ||
try { | ||
decryptedHtml.value = await decryptText(encryptedHtml.value, password.value, iv.value) | ||
trigger.value = true | ||
} | ||
catch (err) { | ||
console.error('Invalid password.') | ||
errored.value = true | ||
return | ||
} | ||
errored.value = false | ||
} | ||
</script> | ||
|
||
<template> | ||
<div id="vp-nolebase-protected"> | ||
<div> | ||
<div relative> | ||
<div flex="~ col" absolute left-0 top-0 z-10 h-full w-full items-center justify-center> | ||
<div mb-4> | ||
<p mt="0!" mb="4!" text-center> | ||
<span font-semibold>You don't have permissions to access this page.</span> | ||
</p> | ||
<p my="0!" text-left> | ||
<span>You could either</span> | ||
<ul my="0!"> | ||
<li my="0!"> | ||
Request an access permission from the owner. | ||
</li> | ||
<li my="0!"> | ||
Prompt a valid password for it. | ||
</li> | ||
</ul> | ||
</p> | ||
</div> | ||
<div w-full flex="~ col" items-center justify-center max-w="80"> | ||
<button | ||
min-w-35 w-full rounded-lg | ||
px-3 py-2 | ||
bg="zinc-700 hover:zinc-600 active:zinc-700 dark:zinc-200 dark:hover:zinc-300 dark:active:zinc-400" | ||
text="zinc-100 dark:zinc-900 " font-semibold | ||
transition="all ease" duration-750 | ||
> | ||
Request Access | ||
</button> | ||
<span>or</span> | ||
<form min-w-35 w-full flex="~ row" @submit.prevent="() => {}"> | ||
<input | ||
v-model="password" | ||
type="password" | ||
mr-2 | ||
w-full rounded-lg | ||
px-3 py-2 | ||
bg="$vp-c-bg" | ||
text="$vp-c-text-1" font-semibold | ||
transition="all ease" duration-750 | ||
:class="[ | ||
errored ? 'outline-offset-1 outline-2 outline-red-400' : 'outline-offset-1 outline-2 outline-zinc-100', | ||
]" | ||
placeholder="Enter the valid password..." | ||
> | ||
<button | ||
rounded-lg | ||
px-3 py-2 | ||
font-semibold | ||
transition="all ease" duration-750 | ||
:class="[ | ||
password !== '' ? 'bg-zinc-700 hover:bg-zinc-600 active:bg-zinc-700 dark:bg-zinc-200 dark:hover:bg-zinc-300 dark:active:bg-zinc-400 text-zinc-100 dark:text-zinc-900' : 'bg-$vp-c-bg cursor-not-allowed! text-$vp-c-text-1', | ||
]" | ||
@click="onPasswordInput" | ||
> | ||
Unlock | ||
</button> | ||
</form> | ||
</div> | ||
</div> | ||
<div blur-md space-y-5> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
<div h="[1lh]" bg="[var(--vp-c-text-1)]" w-full rounded-lg opacity-5 /> | ||
</div> | ||
</div> | ||
<LazyHydrationWrapper :when-triggered="trigger"> | ||
<div id="vp-nolebase-protected-content"> | ||
<slot /> | ||
</div> | ||
<div v-html="decryptedHtml" /> | ||
</LazyHydrationWrapper> | ||
</div> | ||
</div> | ||
</template> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
function useCrypto() { | ||
if (crypto) | ||
return crypto | ||
|
||
if (window.crypto) | ||
return window.crypto | ||
|
||
throw new Error('Crypto not supported') | ||
} | ||
|
||
export async function encryptText(plainText: string, plainTextKey: string) { | ||
const crypto = useCrypto() | ||
|
||
// Encode the key and hash it using SHA-256 | ||
const keyMaterial = await getKeyMaterial(plainTextKey) | ||
const key = await crypto.subtle.importKey( | ||
'raw', | ||
keyMaterial, | ||
{ name: 'AES-GCM', length: 256 }, | ||
false, | ||
['encrypt'], | ||
) | ||
|
||
// Encode the text to be encrypted | ||
const encoder = new TextEncoder() | ||
const encodedText = encoder.encode(plainText) | ||
|
||
// Generate an IV | ||
const iv = window.crypto.getRandomValues(new Uint8Array(12)) | ||
|
||
// Encrypt the text | ||
const encryptedData = await window.crypto.subtle.encrypt( | ||
{ | ||
name: 'AES-GCM', | ||
iv, | ||
}, | ||
key, | ||
encodedText, | ||
) | ||
|
||
// Convert the encrypted data to Base64 | ||
const encryptedText = bufferToBase64(encryptedData) | ||
|
||
// Convert the IV to Base64 | ||
const ivBase64 = bufferToBase64(iv) | ||
|
||
return { encryptedText, ivBase64 } | ||
} | ||
|
||
export async function decryptText(encryptedTextBase64: string, plainTextKey: string, ivBase64: string) { | ||
// Decode the Base64 encrypted text and IV | ||
const encryptedData = base64ToBuffer(encryptedTextBase64) | ||
const iv = base64ToBuffer(ivBase64) | ||
|
||
// Encode the key and hash it using SHA-256 | ||
const keyMaterial = await getKeyMaterial(plainTextKey) | ||
|
||
const key = await window.crypto.subtle.importKey( | ||
'raw', | ||
keyMaterial, | ||
{ name: 'AES-GCM', length: 256 }, | ||
false, | ||
['decrypt'], | ||
) | ||
|
||
// Decrypt the text | ||
const decryptedData = await window.crypto.subtle.decrypt( | ||
{ | ||
name: 'AES-GCM', | ||
iv, | ||
}, | ||
key, | ||
encryptedData, | ||
) | ||
|
||
// Decode the decrypted data | ||
const decoder = new TextDecoder() | ||
return decoder.decode(decryptedData) | ||
} | ||
|
||
// Helper function to convert a Base64 string to an ArrayBuffer | ||
function base64ToBuffer(base64: string): ArrayBuffer { | ||
const binaryString = atob(base64) | ||
const bytes = new Uint8Array(binaryString.length) | ||
for (let i = 0; i < binaryString.length; i++) | ||
bytes[i] = binaryString.charCodeAt(i) | ||
|
||
return bytes.buffer | ||
} | ||
|
||
// Helper function to convert a plaintext string to a SHA-256 hash | ||
async function getKeyMaterial(plainTextKey: string): Promise<ArrayBuffer> { | ||
const crypto = useCrypto() | ||
|
||
const encoder = new TextEncoder() | ||
const keyData = encoder.encode(plainTextKey) | ||
return crypto.subtle.digest('SHA-256', keyData) | ||
} | ||
|
||
// Helper function to convert an ArrayBuffer to a Base64 string | ||
function bufferToBase64(buffer: ArrayBuffer): string { | ||
const bytes = new Uint8Array(buffer) | ||
const binary = bytes.reduce((acc, byte) => acc + String.fromCharCode(byte), '') | ||
return btoa(binary) | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<Protected> | ||
|
||
# Share | ||
|
||
<IntegrationCard type="markdown-it" title="Elements Transformation" package="markdown-it-element-transform" /> | ||
|
||
</Protected> |
This file contains 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
This file contains 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
7 changes: 7 additions & 0 deletions
7
docs/pages/zh-CN/integrations/vitepress-plugin-encrypt/index.md
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<Protected> | ||
|
||
# 分享 | ||
|
||
<IntegrationCard type="markdown-it" title="元素变换" package="markdown-it-element-transform" /> | ||
|
||
</Protected> |
Oops, something went wrong.