Chart.js 3.7.1 Line Chart - How can I format each label individually on the y axis? - chart.js3

I have a line chart. The data is anywhere between -10 and 10.
The labels on the y axis are correct (-10 to 10 incremented by 1).
I need the color of each label to be different, based on an array of colors. The number of labels and the number of colors are both 21 (-10 to 10 including 0).
I'd really like a 'strip' of a gradient so that each label is at the vertical position of the color.
I tried this in the code but learned that html is not available within the chart:
options: {
responsive: true,
plugins: {
title: {
display: true,
text: 'Topic Sentiment'
}
},
scales: {
y: {
title: {
display: true,
text: 'Sentiment Scores'
},
min: -10,
max: 10,
ticks: {
stepSize: 1,
callback: function(value, index, ticks) {
return value + " <div style='height:100%; width:8px; background:" + arColors[index] + ";' ></div>"
}
}
}
},
onClick: (e, activeEls) => {
var oChart = e.chart, label = "";
}
}
This is what I mean. The y gradient is added to an image of the actual chart in Photoshop.
Can I do anything like this?

You can define y.ticks.color as an array of rgb colors. These colors could be generated on the fly.
Inspired by this amazing answer from Pevara, I came up with the following solution:
function hslToRgb(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
}
function yValueToRGB(hue) {
var rgb = hslToRgb(hue, 1, .5);
return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
}
const yTickColors = Array.from(Array(21).keys()).map(v => yValueToRGB(v / 60));
new Chart('canvas', {
type: 'line',
data: {
labels: ['A', 'B', 'C', 'D', 'E', 'F'],
datasets: [{
label: 'Dataset 1',
data: [3, 9, 7, 5, 9, 2],
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgb(255, 99, 132)',
fill: false
},
{
label: 'Dataset 2',
data: [1, 2, -3, -5, -2, 1],
backgroundColor: 'rgba(255, 159, 64, 0.2)',
borderColor: 'rgb(255, 159, 64)'
}
]
},
options: {
scales: {
y: {
max: 10,
min: -10,
ticks: {
stepSize: 1,
autoSkip: false,
color: yTickColors
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<canvas id="canvas"></canvas>

Related

how to calculate sum of every n values in a list?

I have a list that contains some values I want to calculate the sum of every 4 items in this list and then I have to put it in a list.
for example:
list 1=[1,2,3,4,5,6,7,8]
output= [10,26]
You can play with snippet.
final List<int> list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
final List<List<int>> subLists = [];
for (int i = 0; i < list.length / 4; i++) {
final start = i * 4;
final end = i * 4 + 4;
subLists
.add(list.sublist(start, end > list.length ? list.length : end));
}
print(subLists); //[[1, 2, 3, 4], [5, 6, 7, 8], [9]]
final results = subLists
.map((l) => l.reduce((value, element) => value + element))
.toList();
print(results); //[10, 26, 9]
You can use this custom-made extension method to sum every n in a `List``, just add it inside your file outside your classes :
extension SumEveryExtension on List<num> {
List<num> sumEvery(int n) {
num nSumTracker = 0;
List<num> result = [];
for (int index = 0; index < length; index += 1) {
nSumTracker += this[index];
print("current" + nSumTracker.toString());
if ((index +1) % (n ) == 0 && index != 0) {
result.add(nSumTracker);
nSumTracker = 0;
}
}
return result;
}
}
And use it in your code like this:
List<int> list = [1, 2, 3, 4, 5, 6, 7, 8];
print(list.sumEvery(4)); // [10, 26]
You can also customize the n from the method to sum for any other n.

find only same value of that closest to the current index element in an array dart/flutter

I have an array that have same value, so i want to like filter it only for same value that closest to the current index, example :
A[0] = 2,
A[1] = -2,
A[2] = -2,
A[3] = 9,
A[4] = 9,
A[5] = 9,
A[6] = 4,
A[7] = -2,
A[8] = -2,
A[9] = -2,
i want my code can find that the index 1 2 is have same value which is -2 with length 2,
index 3 4 5 have same value 9 with length 3
and index 7 8 9 have same value -2 with length 3 and my code will return only the length of the most in the same value range and closest to index 0 which is value 9
void main() {
var nInt = <ArrayA>[
ArrayA(e: 'A', n: 2),
ArrayA(e: 'A', n: -2),
ArrayA(e: 'A', n: -2),
ArrayA(e: 'A', n: 9),
ArrayA(e: 'A', n: 9),
ArrayA(e: 'A', n: 9),
ArrayA(e: 'A', n: -1),
ArrayA(e: 'A', n: 7),
ArrayA(e: 'A', n: -2),
ArrayA(e: 'A', n: -2),
ArrayA(e: 'A', n: -2),
for (var i = 0; i < nInt.length; i++) {
for (var j = i + 1; j < nInt.length; j++) {
if (nInt[j].n == nInt[i].n) {
} else {
break;
}
}
];
class ArrayA {
final String e;
final int n;
ArrayA({this.e, this.n});
#override
String toString() {
return '$n';
}
}
In-order to achieve that, you need to store the comparison result and nearest index somewhere. For this purpose you can create a class like:
class Counter {
final int index;
final int number;
final int count;
Counter({required this.index, required this.number, required this.count});
#override
String toString() {
return '$count times $number at $index';
}
}
And change the logic to:
var counterValues = <Counter>[];
for (var i = 0; i < nInt.length; i++) {
int count = 1;
int value = nInt[i].n;
for (var j = i + 1; j < nInt.length; j++) {
if (nInt[j].n == nInt[i].n) {
count += 1;
} else {
// Break the inner loop and go to next outer-loop iteration
// You can optimise this by skipping already checked positions (ie: Update i)
break;
}
}
counterValues.add(Counter(index: i, count: count, number: value));
}
And finally to find the most recurring nearest value, you can use the reduce:
var result =
counterValues.reduce((a, b) => (a.count >= b.count && a.index < b.index) ? a : b);
print(result); // Output: 3 times 9 at 3

QuickSort implementation not working for large input

Can anyone tell me why my quickSortHelper function doesn't solve for large input?
import java.util.*;
class Program {
public static int[] quickSort(int[] array) {
// Write your code here.
quickSortHelper(array, 0, array.length - 1);
return array;
}
public static void quickSortHelper(int[] array, int l, int r){
if(l >= r){
return;
}
int pivot = l;
int leftIndex = l + 1;
int rightIndex = r;
while(rightIndex >= leftIndex ){
if(array[leftIndex] > array[pivot] && array[rightIndex] < array[pivot]){
swap(leftIndex, rightIndex, array);
}
if(array[leftIndex] <= array[pivot]){
leftIndex += 1;
}
if(array[rightIndex] >= array[pivot]){
rightIndex -= 1;
}
}
swap(pivot, rightIndex, array);
boolean leftSubarrayIsSmaller = rightIndex - 1 - l < r - (rightIndex + 1);
if(leftSubarrayIsSmaller){
quickSortHelper(array, rightIndex + 1, l);
quickSortHelper(array, l, rightIndex - 1);
}else{
quickSortHelper(array, l, rightIndex - 1);
quickSortHelper(array, rightIndex + 1, l);
}
}
public static void swap(int i, int j, int[] array){
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
Here's my test case, I think if I solve for this it will be an efficient implementation.
int[] array7 = {-4, 5, 10, 8, -10, -6, -4, -2, -5, 3, 5, -4, -5, -1, 1, 6, -7, -6, -7, 8};
The current result is as follows
[-10, -7, -6, -7, -6, -5, -4, -5, -4, 3, 5, -4, -2, -1, 1, 6, 8, 10, 5, 8]
As you can see, still not completely sorted. This does work for smaller input, as in less than 10 numbers.
Any help would be highly appreciated!
Cheers,
You have two lines that look like this, and they do nothing:
quickSortHelper(array, rightIndex + 1, l);
Replace the l with an r:
quickSortHelper(array, rightIndex + 1, r);

Ugly number implementation in scala

I am trying to implement ugly number sequence generation in Scala.
Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15...
I have implemented using var keyword like java implementation and it is working fine. Here is the ideone link of complete code: http://ideone.com/qxMEBw
Can someone suggest better of implementing it using Scala idioms and without using mutable values.
Pasting code here for reference :
/**
* Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence
* 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15,
* shows the first 11 ugly numbers. By convention, 1 is included.
* Write a program to find and print the 150th ugly number.
*
*/
object UglyNumbers extends App {
var uglyNumbers = List(1)
val n = 11
var i2 = 0;
var i3 = 0;
var i5 = 0;
// initialize three choices for the next ugly numbers
var next_multiple_2 = uglyNumbers(i2) * 2;
var next_multiple_3 = uglyNumbers(i3) * 3;
var next_multiple_5 = uglyNumbers(i5) * 5;
for (i <- 0 to n) {
val nextUglyNumber = min(next_multiple_2, next_multiple_3, next_multiple_5)
uglyNumbers = uglyNumbers :+ nextUglyNumber
if (nextUglyNumber == next_multiple_2) {
i2 = i2 + 1
next_multiple_2 = uglyNumbers(i2) * 2
}
if (nextUglyNumber == next_multiple_3) {
i3 = i3 + 1
next_multiple_3 = uglyNumbers(i3) * 3
}
if (nextUglyNumber == next_multiple_5) {
i5 = i5 + 1
next_multiple_5 = uglyNumbers(i5) * 5
}
}
for (uglyNumber <- uglyNumbers)
print(uglyNumber + " ")
def min(a: Int, b: Int, c: Int): Int = (a, b, c) match {
case _ if (a <= b && a <= c) => a
case _ if (b <= a && b <= c) => b
case _ => c
}
}
could take a look at following codes, using stream & recursion:
object App extends App {
val ys = Array(2, 3, 5)
def uglynumber(n: Int): Boolean =
n match {
case x if x == 1 => true
case x if x % 5 == 0 => uglynumber(x / 5)
case x if x % 3 == 0 => uglynumber(x / 3)
case x if x % 2 == 0 => uglynumber(x / 2)
case _ => false
}
def uglynumbers: Stream[Int] = {
def go(x: Int): Stream[Int] =
if (uglynumber(x)) x #:: go(x + 1)
else go(x + 1)
go(1)
}
println(uglynumbers.take(30).toList.sorted)
}
The output for the first 30 ugly numbers:
List(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80)
revise it to use your way
def nums: Stream[Int] = {
def go(a: Int, b: Int, c: Int): Stream[Int] = {
val xs = nums.take(a.max(b.max(c))).toArray
val a2 = 2 * xs(a - 1)
val b3 = 3 * xs(b - 1)
val c5 = 5 * xs(c - 1)
if (a2 <= b3 && a2 <= c5) a2 #:: go(a + 1, b, c)
else if (b3 <= a2 && b3 <= c5) b3 #:: go(a, b + 1, c)
else c5 #:: go(a, b, c + 1)
}
(1 #:: go(1, 1, 1)).distinct
}
println(nums.take(30).toList)
So, how about this one:
scala> lazy val ugly: Stream[Int] = 1 #:: Stream.from(2).filter{ n =>
| ugly.takeWhile(n/2>=).flatten(x => Seq(2, 3, 5).map(x*)).contains(n)
| }
warning: there were 2 feature warning(s); re-run with -feature for details
ugly: Stream[Int] = <lazy>
scala> ugly.take(30).toList
res5: List[Int] = List(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18,
20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80)

node.js hash string?

I have a string that I want to hash. What's the easiest way to generate the hash in node.js?
The hash is for versioning, not security.
If you just want to md5 hash a simple string I found this works for me.
var crypto = require('crypto');
var name = 'braitsch';
var hash = crypto.createHash('md5').update(name).digest('hex');
console.log(hash); // 9b74c9897bac770ffc029102a200c5de
Take a look at crypto.createHash(algorithm)
var filename = process.argv[2];
var crypto = require('crypto');
var fs = require('fs');
var md5sum = crypto.createHash('md5');
var s = fs.ReadStream(filename);
s.on('data', function(d) {
md5sum.update(d);
});
s.on('end', function() {
var d = md5sum.digest('hex');
console.log(d + ' ' + filename);
});
Node's crypto module API is still unstable.
As of version 4.0.0, the native Crypto module is not unstable anymore. From the official documentation:
Crypto
Stability: 2 - Stable
The API has proven satisfactory. Compatibility with the npm ecosystem
is a high priority, and will not be broken unless absolutely necessary.
So, it should be considered safe to use the native implementation, without external dependencies.
For reference, the modules mentioned bellow were suggested as alternative solutions when the Crypto module was still unstable.
You could also use one of the modules sha1 or md5 which both do the job.
$ npm install sha1
and then
var sha1 = require('sha1');
var hash = sha1("my message");
console.log(hash); // 104ab42f1193c336aa2cf08a2c946d5c6fd0fcdb
or
$ npm install md5
and then
var md5 = require('md5');
var hash = md5("my message");
console.log(hash); // 8ba6c19dc1def5702ff5acbf2aeea5aa
(MD5 is insecure but often used by services like Gravatar.)
The API of these modules won't change!
sha256("string or binary");
I experienced issue with other answer. I advice you to set encoding argument to binary to use the byte string and prevent different hash between Javascript (NodeJS) and other langage/service like Python, PHP, Github...
If you don't use this code, you can get a different hash between NodeJS and Python...
How to get the same hash that Python, PHP, Perl, Github (and prevent an issue) :
NodeJS is hashing the UTF-8 representation of the string. Other languages (like Python, PHP or PERL...) are hashing the byte string.
We can add binary argument to use the byte string.
Code :
const crypto = require("crypto");
function sha256(data) {
return crypto.createHash("sha256").update(data, "binary").digest("base64");
// ------ binary: hash the byte string
}
sha256("string or binary");
Documentation:
crypto.createHash(algorithm[, options]): The algorithm is dependent on the available algorithms supported by the version of OpenSSL on the platform.
hash.digest([encoding]): The encoding can be 'hex', 'latin1' or 'base64'. (base 64 is less longer).
You can get the issue with : sha256("\xac"), "\xd1", "\xb9", "\xe2", "\xbb", "\x93", etc...
Other languages (like PHP, Python, Perl...) and my solution with .update(data, "binary") :
sha1("\xac") //39527c59247a39d18ad48b9947ea738396a3bc47
Nodejs by default (without binary) :
sha1("\xac") //f50eb35d94f1d75480496e54f4b4a472a9148752
Simple One Liners:
If you want UTF8 text hash:
const hash = require('crypto').createHash('sha256').update('Hash me', 'utf8').digest('hex');
If you want to get the same hash with Python, PHP, Perl, Github:
const hash = require('crypto').createHash('sha256').update('Hash me', 'binary').digest('hex');
You can also replace 'sha256' with 'sha1', 'md5', 'sha256', 'sha512'
The crypto module makes this very easy.
Setup:
// import crypto from 'crypto';
const crypto = require('crypto');
const sha256 = x => crypto.createHash('sha256').update(x, 'utf8').digest('hex');
Usage:
sha256('Hello, world. ');
Here you can benchmark all supported hashes on your hardware, supported by your version of node.js. Some are cryptographic, and some is just for a checksum. Its calculating "Hello World" 1 million times for each algorithm. It may take around 1-15 seconds for each algorithm (Tested on the Standard Google Computing Engine with Node.js 4.2.2).
for(var i1=0;i1<crypto.getHashes().length;i1++){
var Algh=crypto.getHashes()[i1];
console.time(Algh);
for(var i2=0;i2<1000000;i2++){
crypto.createHash(Algh).update("Hello World").digest("hex");
}
console.timeEnd(Algh);
}
Result:
DSA: 1992ms
DSA-SHA: 1960ms
DSA-SHA1: 2062ms
DSA-SHA1-old: 2124ms
RSA-MD4: 1893ms
RSA-MD5: 1982ms
RSA-MDC2: 2797ms
RSA-RIPEMD160: 2101ms
RSA-SHA: 1948ms
RSA-SHA1: 1908ms
RSA-SHA1-2: 2042ms
RSA-SHA224: 2176ms
RSA-SHA256: 2158ms
RSA-SHA384: 2290ms
RSA-SHA512: 2357ms
dsaEncryption: 1936ms
dsaWithSHA: 1910ms
dsaWithSHA1: 1926ms
dss1: 1928ms
ecdsa-with-SHA1: 1880ms
md4: 1833ms
md4WithRSAEncryption: 1925ms
md5: 1863ms
md5WithRSAEncryption: 1923ms
mdc2: 2729ms
mdc2WithRSA: 2890ms
ripemd: 2101ms
ripemd160: 2153ms
ripemd160WithRSA: 2210ms
rmd160: 2146ms
sha: 1929ms
sha1: 1880ms
sha1WithRSAEncryption: 1957ms
sha224: 2121ms
sha224WithRSAEncryption: 2290ms
sha256: 2134ms
sha256WithRSAEncryption: 2190ms
sha384: 2181ms
sha384WithRSAEncryption: 2343ms
sha512: 2371ms
sha512WithRSAEncryption: 2434ms
shaWithRSAEncryption: 1966ms
ssl2-md5: 1853ms
ssl3-md5: 1868ms
ssl3-sha1: 1971ms
whirlpool: 2578ms
I had to throw my 2 cents in hope this helps someone out.
For those using CommonJS
const crypto = require('crypto');
const secret = 'I love writing code, fixing things and building helpful tools';
const hash = crypto.createHmac('sha256', secret).digest('hex');
console.log('Hash successfully generated: ', hash);
For those using ES Modules
const { createHmac } = await import('crypto');
const secret = 'I love writing code, fixing things and building helpful tools';
const hash = createHmac('sha256', secret).digest('hex');
console.log('Hash successfully generated: ', hash);
Super simple!
Happy Coding :)
I use blueimp-md5 which is "Compatible with server-side environments like Node.js, module loaders like RequireJS, Browserify or webpack and all web browsers."
Use it like this:
var md5 = require("blueimp-md5");
var myHashedString = createHash('GreensterRox');
createHash(myString){
return md5(myString);
}
If passing hashed values around in the open it's always a good idea to salt them so that it is harder for people to recreate them:
createHash(myString){
var salt = 'HnasBzbxH9';
return md5(myString+salt);
}
function md5(a) {
var r = 0,
c = "";
return h(a);
function h(t) {
return u(l(m(t)))
}
function l(t) {
return p(g(f(t), 8 * t.length))
}
function u(t) {
for (var e, i = r ? "0123456789ABCDEF" : "0123456789abcdef", n = "", o = 0; o < t.length; o++)
e = t.charCodeAt(o),
n += i.charAt(e >>> 4 & 15) + i.charAt(15 & e);
return n
}
function m(t) {
for (var e, i, n = "", o = -1; ++o < t.length;)
e = t.charCodeAt(o),
i = o + 1 < t.length ? t.charCodeAt(o + 1) : 0,
55296 <= e && e <= 56319 && 56320 <= i && i <= 57343 && (e = 65536 + ((1023 & e) << 10) + (1023 & i),
o++),
e <= 127 ? n += String.fromCharCode(e) : e <= 2047 ? n += String.fromCharCode(192 | e >>> 6 & 31, 128 | 63 & e) : e <= 65535 ? n += String.fromCharCode(224 | e >>> 12 & 15, 128 | e >>> 6 & 63, 128 | 63 & e) : e <= 2097151 && (n += String.fromCharCode(240 | e >>> 18 & 7, 128 | e >>> 12 & 63, 128 | e >>> 6 & 63, 128 | 63 & e));
return n
}
function f(t) {
for (var e = Array(t.length >> 2), i = 0; i < e.length; i++)
e[i] = 0;
for (i = 0; i < 8 * t.length; i += 8)
e[i >> 5] |= (255 & t.charCodeAt(i / 8)) << i % 32;
return e
}
function p(t) {
for (var e = "", i = 0; i < 32 * t.length; i += 8)
e += String.fromCharCode(t[i >> 5] >>> i % 32 & 255);
return e
}
function g(t, e) {
t[e >> 5] |= 128 << e % 32,
t[14 + (e + 64 >>> 9 << 4)] = e;
for (var i = 1732584193, n = -271733879, o = -1732584194, s = 271733878, a = 0; a < t.length; a += 16) {
var r = i,
c = n,
h = o,
l = s;
n = E(n = E(n = E(n = E(n = N(n = N(n = N(n = N(n = C(n = C(n = C(n = C(n = S(n = S(n = S(n = S(n, o = S(o, s = S(s, i = S(i, n, o, s, t[a + 0], 7, -680876936), n, o, t[a + 1], 12, -389564586), i, n, t[a + 2], 17, 606105819), s, i, t[a + 3], 22, -1044525330), o = S(o, s = S(s, i = S(i, n, o, s, t[a + 4], 7, -176418897), n, o, t[a + 5], 12, 1200080426), i, n, t[a + 6], 17, -1473231341), s, i, t[a + 7], 22, -45705983), o = S(o, s = S(s, i = S(i, n, o, s, t[a + 8], 7, 1770035416), n, o, t[a + 9], 12, -1958414417), i, n, t[a + 10], 17, -42063), s, i, t[a + 11], 22, -1990404162), o = S(o, s = S(s, i = S(i, n, o, s, t[a + 12], 7, 1804603682), n, o, t[a + 13], 12, -40341101), i, n, t[a + 14], 17, -1502002290), s, i, t[a + 15], 22, 1236535329), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 1], 5, -165796510), n, o, t[a + 6], 9, -1069501632), i, n, t[a + 11], 14, 643717713), s, i, t[a + 0], 20, -373897302), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 5], 5, -701558691), n, o, t[a + 10], 9, 38016083), i, n, t[a + 15], 14, -660478335), s, i, t[a + 4], 20, -405537848), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 9], 5, 568446438), n, o, t[a + 14], 9, -1019803690), i, n, t[a + 3], 14, -187363961), s, i, t[a + 8], 20, 1163531501), o = C(o, s = C(s, i = C(i, n, o, s, t[a + 13], 5, -1444681467), n, o, t[a + 2], 9, -51403784), i, n, t[a + 7], 14, 1735328473), s, i, t[a + 12], 20, -1926607734), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 5], 4, -378558), n, o, t[a + 8], 11, -2022574463), i, n, t[a + 11], 16, 1839030562), s, i, t[a + 14], 23, -35309556), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 1], 4, -1530992060), n, o, t[a + 4], 11, 1272893353), i, n, t[a + 7], 16, -155497632), s, i, t[a + 10], 23, -1094730640), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 13], 4, 681279174), n, o, t[a + 0], 11, -358537222), i, n, t[a + 3], 16, -722521979), s, i, t[a + 6], 23, 76029189), o = N(o, s = N(s, i = N(i, n, o, s, t[a + 9], 4, -640364487), n, o, t[a + 12], 11, -421815835), i, n, t[a + 15], 16, 530742520), s, i, t[a + 2], 23, -995338651), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 0], 6, -198630844), n, o, t[a + 7], 10, 1126891415), i, n, t[a + 14], 15, -1416354905), s, i, t[a + 5], 21, -57434055), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 12], 6, 1700485571), n, o, t[a + 3], 10, -1894986606), i, n, t[a + 10], 15, -1051523), s, i, t[a + 1], 21, -2054922799), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 8], 6, 1873313359), n, o, t[a + 15], 10, -30611744), i, n, t[a + 6], 15, -1560198380), s, i, t[a + 13], 21, 1309151649), o = E(o, s = E(s, i = E(i, n, o, s, t[a + 4], 6, -145523070), n, o, t[a + 11], 10, -1120210379), i, n, t[a + 2], 15, 718787259), s, i, t[a + 9], 21, -343485551),
i = v(i, r),
n = v(n, c),
o = v(o, h),
s = v(s, l)
}
return [i, n, o, s]
}
function _(t, e, i, n, o, s) {
return v((a = v(v(e, t), v(n, s))) << (r = o) | a >>> 32 - r, i);
var a, r
}
function S(t, e, i, n, o, s, a) {
return _(e & i | ~e & n, t, e, o, s, a)
}
function C(t, e, i, n, o, s, a) {
return _(e & n | i & ~n, t, e, o, s, a)
}
function N(t, e, i, n, o, s, a) {
return _(e ^ i ^ n, t, e, o, s, a)
}
function E(t, e, i, n, o, s, a) {
return _(i ^ (e | ~n), t, e, o, s, a)
}
function v(t, e) {
var i = (65535 & t) + (65535 & e);
return (t >> 16) + (e >> 16) + (i >> 16) << 16 | 65535 & i
}
}
string = 'hello';
console.log(md5(string));
Considering the thoughts from
http://www.thoughtcrime.org/blog/the-cryptographic-doom-principle/
(in short: FIRST encrypt, THEN authenticate. Afterwards FIRST verify, THEN decrypt)
I have implemented the following solution in node.js:
function encrypt(text,password){
var cipher = crypto.createCipher(algorithm,password)
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
function decrypt(text,password){
var decipher = crypto.createDecipher(algorithm,password)
var dec = decipher.update(text,'hex','utf8')
dec += decipher.final('utf8');
return dec;
}
function hashText(text){
var hash = crypto.createHash('md5').update(text).digest("hex");
//console.log(hash);
return hash;
}
function encryptThenAuthenticate(plainText,pw)
{
var encryptedText = encrypt(plainText,pw);
var hash = hashText(encryptedText);
return encryptedText+"$"+hash;
}
function VerifyThenDecrypt(encryptedAndAuthenticatedText,pw)
{
var encryptedAndHashArray = encryptedAndAuthenticatedText.split("$");
var encrypted = encryptedAndHashArray[0];
var hash = encryptedAndHashArray[1];
var hash2Compare = hashText(encrypted);
if (hash === hash2Compare)
{
return decrypt(encrypted,pw);
}
}
It can be tested with:
var doom = encryptThenAuthenticate("The encrypted text",user.cryptoPassword);
console.log(VerifyThenDecrypt(doom,user.cryptoPassword));
Hope this helps :-)
Even if the hash is not for security, you can use sha instead of md5. In my opinion, the people should forget about md5 for now, it's in the past!
The normal nodejs sha256 is deprecated. So, you have two alternatives for now:
var shajs = require('sha.js') - https://www.npmjs.com/package/sha.js (used by Browserify)
var hash = require('hash.js') - https://github.com/indutny/hash.js
I prefer using shajs instead of hash, because I consider sha the best hash function nowadays and you don't need a different hash function for now. So to get some hash in hex you should do something like the following:
sha256.update('hello').digest('hex')
you can use crypto-js javaScript library of crypto standards, there is easiest way to generate sha256 or sha512
const SHA256 = require("crypto-js/sha256");
const SHA512 = require("crypto-js/sha512");
let password = "hello"
let hash_256 = SHA256 (password).toString();
let hash_512 = SHA512 (password).toString();
Password hashing in NodeJs using PBKDF2
const pbkdf2 = require("pbkdf2");
const crypto = require("crypto");
// UserSchema
//...
// Method to create pbkdf2 hash from plain text
UserSchema.methods.createHash = async function (plainTextPassword) {
// Generate a salt and then create hash
const salt = crypto.randomBytes(16).toString("hex");
const hashedPassword = pbkdf2
.pbkdf2Sync(plainTextPassword, salt, 10, 32, "sha512")
.toString("hex");
// Saving both the dynamic salt and hash in the Database
return [salt, hashedPassword].join("#");
};
// Validating the password with pbkdf2 hash
UserSchema.methods.validatePassword = async function (candidatePassword) {
const hashedPassword = this.password_hash.split("#")[1];
const salt = this.password_hash.split("#")[0];
const hash = pbkdf2
.pbkdf2Sync(candidatePassword, salt, 10, 32, "sha512")
.toString("hex");
if (hash === hashedPassword) {
return true;
}
return false;
};
module.exports.User = mongoose.model("User", UserSchema);
Password hashing in NodeJs using Argon2
const argon2 = require("argon2");
// UserSchema
...
// Method to generate Hash from plain text using argon2
UserSchema.methods.createHash = async function (plainTextPassword) {
// return password hash
return await argon2.hash(plainTextPassword);
};
// Method to validate the entered password using argon2
UserSchema.methods.validatePassword = async function (candidatePassword) {
return await argon2.verify(this.password_hash, candidatePassword)
};
module.exports.User = mongoose.model("User", UserSchema);
This article can help in setup to execute with a demo project.
https://mojoauth.com/blog/hashing-passwords-in-nodejs/