Reputation: 320
I have created my own hash.js file that requires crypto and exports two functions that use crypto. It works fine in my api.js file when I hash passwords. However Now I am trying to import this file in my user.service.ts file so that I can send the hashed version of the password as a query parameter instead of the password itself. When I try to do so I always get a TypeScript error telling me that the functions crypto uses are not functions. However I can still console log the object I import and it looks legit to me. I looked at other java script files in the node_modules folder and I cannot see anything that should be wrong with my file.
I have also found out that there seems to be some definition file that I need to create but I have also had many attempts at creating such a file but nothing seems to work
A few hours of googling and the lack of knowledge amongst lack of time on this project led me to this post, it is my first stackoverflow post and I hope that it is not to unclear and I am glad to provide any information needed to help me resolve this issue.
LoginComponent.html:18 ERROR TypeError: crypto.randomBytes is not a function
at Object.genRandomString (hash.js:12)
at UserService.loginUser (user.service.ts:82)
at LoginComponent.getUser (login.component.ts:54)
at LoginComponent.onSubmit (login.component.ts:44)
at Object.eval [as handleEvent] (LoginComponent.html:18)
at handleEvent (core.es5.js:12014)
at callWithDebugContext (core.es5.js:13475)
at Object.debugHandleEvent [as handleEvent] (core.es5.js:13063)
at dispatchEvent (core.es5.js:8607)
at core.es5.js:10775
LoginComponent.html:18 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 31, nodeDef: {…}, elDef: {…}, elView: {…}}
the hash.js file
'use strict';
var crypto = require('crypto');
/**
* generates random string of characters i.e salt
* @function
* @param {number} length - Length of the random string.
*/
function genRandomString (length){
return crypto.randomBytes(Math.ceil(length/2))
.toString('hex') /** convert to hexadecimal format */
.slice(0,length); /** return required number of characters */
};
/**
* hash password with sha512.
* @function
* @param {string} password - List of required fields.
* @param {string} salt - Data to be validated.
*/
function sha512(password, salt){
var hash = crypto.createHmac('sha512', salt); /** Hashing algorithm sha512 */
hash.update(password);
var value = hash.digest('hex');
return {
salt:salt,
passwordHash:value
};
};
module.exports = {
genRandomString: genRandomString,
sha512: sha512
};
Upvotes: 32
Views: 85846
Reputation: 506
The way I resolved this issue was to add the following to my package.json file, right after the devDependencies section.
"devDependencies": {
...
},
"browser": {
"crypto": false
}
Upvotes: 0
Reputation: 3363
There seems to be some confusion mixing JavaScript and TypeScript, but since I came across this issue myself, here is how I solved it.
First, your hash.js file should be hash.ts. Then you can import crypto and use it normally. Related code below:
import * as crypto from "crypto";
public setEncryptionKeyDES(sKey: string) {
const desIV = Buffer.alloc(8);
this.encLobby.cipher = crypto.createCipheriv(
"des-cbc",
Buffer.from(sKey, "hex"),
desIV,
);
this.encLobby.cipher.setAutoPadding(false);
this.encLobby.decipher = crypto.createDecipheriv(
"des-cbc",
Buffer.from(sKey, "hex"),
desIV,
);
this.encLobby.decipher.setAutoPadding(false);
this.isSetupComplete = true;
}
Edit1: Adding @attdona's answer from below, make sure you install @types/node
into your project as well, or you will receive many errors related to node modules not being found.
Upvotes: 43
Reputation: 18953
Just hitted this issue (node v13.12.0, tsc v3.8.3). In my case the import:
import * as crypto from "crypto";
gives the error:
error TS2307: Cannot find module 'crypto'
because I have to install types definition for node: it includes crypto ambient declarations.
npm install @types/node
Note: If you have a global install of @types/node
then you have to explicitly declare the path where @types
are located with --typesRoot
option.
See here for details.
Upvotes: 17
Reputation: 177
Well this turned out to be a rather horrific rabbit hole to go down. I followed a bunch of recommended suggestions but ultimately the solution that worked for me was (as always...) super-simple, ONCE you know how.
The answer was to use the browser built-in crypto functionality. I only wanted to check a one-way digest of a password as being sufficient for a very lightweight app. However most guides were only partial suggestions, or didn't work with my app's setup of using Angular 7 and babel. So here's the final code I ended up with, with the following notes:
Anyway here's the code, hope it helps other Stack Overflowers.
I also found Daniel Roesler's Github page very useful for implementations of various web cryptography examples.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-user-create',
templateUrl: './user-create.component.html',
styleUrls: ['./user-create.component.css']
})
export class UserCreateComponent implements OnInit {
constructor() { }
ngOnInit() {
sha256("hello").then(digestValue => {
console.log(digestValue);
});
}
}
async function sha256(str) {
const encoder = new TextEncoder();
const encdata = encoder.encode(str);
const buf = await crypto.subtle.digest("SHA-256", encdata);
return Array.prototype.map.call(new Uint8Array(buf), x=>(('00'+x.toString(16)).slice(-2))).join('');
}
Upvotes: 1
Reputation: 19764
When I try to do so I always get a TypeScript error telling me that the functions crypto uses are not functions.
This is happening because TypeScript statically analyzes your files and tries to help you with types of data that you're working with. If you're using a function written in JavaScript without any hint to TypeScript about what this function is using as arguments and what is the type of its return value, it simply cannot do its job, which is why you're getting an error.
You could create a decalration file, but you do not need to if you want a quick fix and if you won't be using these raw JS functions in other files. You just need to declare it anywhere in the file. You can read more about using declare
keyword in TypeScript.
However I can still console log the object I import and it looks legit to me.
Judging by your screenshot, the function randomBytes
is called properly (as you can see from the stack trace printed below the error). The problem is that the crypto
object does not contain a method named randomBytes
. This is because crypto
is a global object in newer browsers.
Your crypto.js
file is probably assuming existence of a different crypto
global object than what browser has. Either provide this object in the proper scope so your function can see it, or inline those functions using a bundler such as Rollup.
Upvotes: 1