Open oscartbeaumont opened 2 years ago
Wow, nice! I was here to create a ticket that it isn't running on Deno Deploy. Thank you very much for your help and work ;)
Thanks for raising the issue, I'm sure it'll help a lot of people out. However, this operation is blocking so running it non-async isn't the intended use case and can cause issues (e.g. if many requests hit a server at once) so while it may work for you, I don't think adding it to the library would be wise.
I'll close the issue if/when deno-deploy supports workers (please let me know since I don't follow deno-deploy closely) and leave it open for now so others can find it. Thanks again for sharing your workaround!
This issues hits also deno compile
. Anyone has a way to detect this case?
I’m finding a weird issue that just started this week. compare function returns false for older accounts and true for new accounts created this week.
If I restart systemd which I use to start deno it sometimes works for older accounts but then newer ones can’t login.
I’m completely baffled. Deployed to Ubuntu 20.04 using latest stable deno.
Y suspicion is a recent deno upgrade broke it.
I don't maintain this repository but it looks like someone reported this as issue #27. I don't understand how it is related to this issue about Deno Deploy so it's discussion should be done in a separate issue unless it has a direct link.
Love you dawg, i was just searching for this
Thank you so much man, this really helped !
Currently
hash
andcompare
are not supported when deploying code on Deno Deploy. This is due toWorker
not being defined refer to upstream issue.However, until
Worker
is implemented with Deno Deploy you can use thehashSync
andcompareSync
methods.I have included a helper below which allows for easily switching between these two methods for anyone working on a codebase designed to run efficiently locally and inside Deno Deploy.
import { hash as hashPromise, hashSync, compare as comparePromise, compareSync, } from "https://deno.land/x/bcrypt/mod.ts"; export const isRunningInDenoDeploy = Deno.permissions?.query === undefined; // This is crude check for if the code in running in Deno Deploy. It works for now but may not work in the future. export const hash: typeof hashPromise = isRunningInDenoDeploy ? (plaintext: string, salt: string | undefined = undefined) => new Promise((res) => res(hashSync(plaintext, salt))) : hashPromise; export const compare: typeof comparePromise = isRunningInDenoDeploy ? (plaintext: string, hash: string) => new Promise((res) => res(compareSync(plaintext, hash))) : comparePromise;
I primarily created this issue to help anyone who runs into the same issue. It would be cool to see the helpers I included added to this library but I think this would be unlikely given how hacky it is.
isRunningInDenoDeploy
should be checked through the environment variables in the project.
Is there any status update concerning this? SInce deno deploy has the web crypto API, it might be the Worker never will be implemented.
Is there a way we could use the web crypto API instead of the sync ways with bcrypt?
@AshwinDeTaeye This is a problem with Deno Deploy not supporting Workers. If you need to run your app on Deno Deploy, it seems that the only option right now is to have these calls blocking and use the sync methods.
I'm not quite sure what you mean by using the Web Crypto API instead of Workers.
Upstream issue previously mentioned here: https://github.com/denoland/deploy_feedback/issues/171
Deno deploy does support the Web Crypto API. https://deno.com/deploy/docs/runtime-api I suppose there should be async ways of achieving hash and compare through this API.
What i found: https://bradyjoslin.com/blog/encryption-webcrypto/
Do you think this could be done with this API?
To be honest, I've not really kept up with Deno anymore and I'm not prepared to overhaul this code just to support Deno Deploy because it doesn't support Workers. If you do manage to find a way, please do keep us posted so others interested in the thread know. Thanks 😄
We can use the standard lib from Deno, Web Crypto, to be able to do async hashing. Following worked for me in Deno deploy:
const buff_to_base64 = (buff: number[] | Uint8Array) =>
btoa(String.fromCharCode.apply(null, buff));
const base64_to_buf = (b64: string) =>
Uint8Array.from(atob(b64), (c) => c.charCodeAt(null));
const enc = new TextEncoder();
const dec = new TextDecoder();
const getPasswordKey = async (password: any) =>
await window.crypto.subtle.importKey(
"raw",
enc.encode(password),
"PBKDF2",
false,
['deriveBits', "deriveKey"]
);
const deriveKey = async (passwordKey: any, salt: any, keyUsage: any[]) =>
await window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 250000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
keyUsage
);
export async function encryptData(secretData: string | undefined, password: any) {
try {
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ["encrypt"]);
const encryptedContent = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
enc.encode(secretData)
);
const encryptedContentArr = new Uint8Array(encryptedContent);
let buff = new Uint8Array(
salt.byteLength + iv.byteLength + encryptedContentArr.byteLength
);
buff.set(salt, 0);
buff.set(iv, salt.byteLength);
buff.set(encryptedContentArr, salt.byteLength + iv.byteLength);
const base64Buff = buff_to_base64(buff);
return base64Buff;
} catch (e) {
console.log(`Error - ${e}`);
return "";
}
}
export async function decryptData(
encryptedData: string,
password: string | undefined
) {
try {
const encryptedDataBuff = base64_to_buf(encryptedData);
const salt = encryptedDataBuff.slice(0, 16);
const iv = encryptedDataBuff.slice(16, 16 + 12);
const data = encryptedDataBuff.slice(16 + 12);
const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ["decrypt"]);
const decryptedContent = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
data
);
return dec.decode(decryptedContent);
} catch (e) {
console.log(`Error - ${e}`);
return "";
}
}
For the proposed solution in the OP, I think a more sensible way to detect if it'll work is by using
// deno-lint-ignore no-explicit-any
export const isRunningInDenoDeploy = (globalThis as any).Worker === undefined;
For the proposed solution in the OP, I think a more sensible way to detect if it'll work is by using
// deno-lint-ignore no-explicit-any export const isRunningInDenoDeploy = (globalThis as any).Worker === undefined;
^ This suggestion worked for me, however an alternative solution could be to set an environment variable such as Deno.env.Get('DENO_ENV') === 'production'
For the proposed solution in the OP, I think a more sensible way to detect if it'll work is by using
// deno-lint-ignore no-explicit-any export const isRunningInDenoDeploy = (globalThis as any).Worker === undefined;
^ This suggestion worked for me, however an alternative solution could be to set an environment variable such as
Deno.env.Get('DENO_ENV') === 'production'
That's actually what I ended up going with, because of another library that I needed to know which environment I was in. Just didn't post it here lol
Currently
hash
andcompare
are not supported when deploying code on Deno Deploy. This is due toWorker
not being defined refer to upstream issue.However, until
Worker
is implemented with Deno Deploy you can use thehashSync
andcompareSync
methods.I have included a helper below which allows for easily switching between these two methods for anyone working on a codebase designed to run efficiently locally and inside Deno Deploy.
I primarily created this issue to help anyone who runs into the same issue. It would be cool to see the helpers I included added to this library but I think this would be unlikely given how hacky it is.