The fe(JS)&be(Python) coupling of RSA encryption

I am using RSA algorithm to encrypt data. The frontend uses the window.crypto and the backend uses the pycryptodome.

However, I discovered that after the frontend encrypts a payload, the backend can’t decrypt it. The frontend refers MDN‘s example code: https://github.com/mdn/dom-examples/blob/main/web-crypto/import-key/spki.js, and my code is not shown on GitHub now. The backend is copied from the example which is written by myself: https://github.com/zvms/rsa-bcrypt-jwt-login-eg/blob/main/cert.py. The full code is showed here:

Frontend

crpyto.ts

// Function to convert PEM formatted public key to a CryptoKey object
async function importPublicKey(pemKey: string) {
  const withoutNewlines = pemKey
    .replace('-----BEGIN PUBLIC KEY-----', '')
    .replace('-----END PUBLIC KEY-----', '')
    .split('n')
    .filter((line) => line.trim() !== '')
    .join('')
  console.log(withoutNewlines)
  // Base64 decode the string to get the binary data
  const binaryDerString = window.atob(withoutNewlines)
  // Convert from a binary string to an ArrayBuffer
  const binaryDer = str2ab(binaryDerString)

  return window.crypto.subtle.importKey(
    'spki',
    binaryDer,
    {
      name: 'RSA-OAEP',
      hash: 'SHA-256' // Specify the hash algorithm
    },
    true,
    ['encrypt']
  )
}

// Utility function to convert a binary string to an ArrayBuffer
function str2ab(str: string) {
  const buf = new ArrayBuffer(str.length)
  const bufView = new Uint8Array(buf)
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i)
  }
  return buf
}

// Function to encrypt data using RSA-OAEP
async function encryptData(publicKey: CryptoKey, data: string) {
  const encoder = new TextEncoder()
  const encodedData = encoder.encode(data)

  const encryptedData = await window.crypto.subtle.encrypt(
    {
      name: 'RSA-OAEP'
    },
    publicKey,
    encodedData
  )

  return encryptedData
}

export { importPublicKey, encryptData }

auth.ts

async function UserLogin(user: string, password: string, term: 'long' | 'short' = 'long') {
  const payload = JSON.stringify({
    password: password,
    time: Date.now()
  })
  const publicKey = await importPublicKey(await getRSAPublicCert())
  const credential = await encryptData(publicKey, payload)
  // console.log(credential)
  const hex = byteArrayToHex(new Uint8Array(credential))
  console.log(`User ${user} login with ${term} term, with the credential ${hex}`)
  const result = (await axios('/user/auth', {
    method: 'POST',
    data: {
      id: user.toString(),
      credential: hex,
      mode: term
    }
  })) as Response<LoginResult>
}

Backend

import bcrypt
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from fastapi import HTTPException
import jwt
import json
import datetime
from database import db
from bson import ObjectId
from bcrypt import checkpw


class Auth:
    password: str
    time: int


def hash_password(password):
    return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())


def check_password(password, hashed):
    return bcrypt.checkpw(password.encode("utf-8"), hashed)


public_key = RSA.import_key(open("rsa_public_key.pem", "rb").read())
private_key = RSA.import_key(open("rsa_private_key.pem", "rb").read())
jwt_private_key = open("aes_key.txt", "r").read()


def rsa_encrypt(plaintext):
    cipher = PKCS1_OAEP.new(public_key)
    encrypt_text = cipher.encrypt(bytes(plaintext.encode("utf8")))
    return encrypt_text.hex()


def rsa_decrypt(ciphertext):
    cipher = PKCS1_OAEP.new(private_key)
    decrypt_text = cipher.decrypt(bytes.fromhex(ciphertext))
    return decrypt_text.decode("utf8")


def jwt_encode(id: str):
    payload = {
        "exp": datetime.datetime.utcnow() + datetime.timedelta(seconds=60),
        "iat": datetime.datetime.utcnow(),
        "sub": id,
        "scope": "access_token",
        "type": "long-term",
    }
    return jwt.encode(payload, jwt_private_key, algorithm="HS256")


def jwt_decode(token):
    return jwt.decode(token, jwt_private_key, algorithms=["HS256"], verify=True)


def validate_by_cert(id: str, cert: str):
    auth_field = json.loads(rsa_decrypt(cert))
    time = auth_field["time"]
    # in a minute
    if time > datetime.datetime.now().timestamp() + 60:
        raise HTTPException(status_code=401, detail="Token expired")

    if checkpwd(id, auth_field["password"]):
        raise HTTPException(status_code=401, detail="Password incorrect")

    return jwt_encode(id)

def checkpwd(id: str, pwd: str):
    user = db.zvms.users.find_one({"_id": ObjectId(id)})
    if checkpw(bytes(pwd, 'utf-8'), user.get('password')):
        return True
    return False

and the api handler directly calls validate_by_cert method.

Key Generation

Directly use openssl.

openssl genrsa -out rsa_private_key.pem 1024
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
openssl rand -hex 32 > aes_key.txt

Behavior

It returns error when calling this api:

  File "/Users/*/**/zvms/routers/users_router.py", line 43, in auth_user
    result = validate_by_cert(id, credential)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/*/**/zvms/util/cert.py", line 59, in validate_by_cert
    auth_field = json.loads(rsa_decrypt(cert))
                            ^^^^^^^^^^^^^^^^^
  File "/Users/*/**/zvms/util/cert.py", line 39, in rsa_decrypt
    decrypt_text = cipher.decrypt(bytes.fromhex(ciphertext))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/*/anaconda3/envs/zvms/lib/python3.12/site-packages/Crypto/Cipher/PKCS1_OAEP.py", line 191, in decrypt
    raise ValueError("Incorrect decryption.")

However, when I call the native rsa_encrypt method and use it to decrypt, it works well.

The frontend and backend can transfer encrypted data successfully.

2D array to be filled with false values returns array where first values are true

I am trying to initialise a 2D array which is filled with exclusively false values. I have tried several different methods of creating this array (of which I will place below) and have seen the same (or weirder) results for all of them.

A:

const gridSize = 16;
let cells = Array.from(Array(gridSize), () => new Array(gridSize).fill(false));
console.log(cells);

B:

function createGrid(){ 
let cells = [];
  for(let x = 0; x < gridSize; x++){
    cells[x] = [];
    for(let y = 0; y < gridSize; y++){
      cells[x][y] = false;
    }
  }
  console.log(cells);
  // console.log(cells);
  return cells;
}

let cells = [];

function setup(){
  cells = createGrid();
}

Output is same for both:
Array values in internet edge console for A and B separately

And then strangely, when A and B are both included in code:

const gridSize = 16;
let cells = Array.from(Array(gridSize), () => new Array(gridSize).fill(false));
console.log(cells);

function setup() {
  cells = createGrid();
}

Output:

Array values in internet edge console for A and B combined

My friend and I are unable to comprehend what could be going wrong and are very confused.

My entire code

How to let vite print the functions that are polyfilled for the production build?

This bug report includes the following output from vite:

vite v2.9.9 building for production...
✓ 4 modules transformed.
rendering chunks (1)...[@vitejs/plugin-legacy] modern polyfills: Set(4) {
  'core-js/modules/es.array.iterator.js',
  'core-js/modules/web.dom-collections.iterator.js',
  'core-js/modules/es.promise.js',
  'core-js/modules/es.regexp.exec.js'
}
dist/assets/favicon.17e50649.svg           1.49 KiB
dist/index.html                            0.53 KiB
dist/assets/index.e9192aae.js              0.91 KiB / gzip: 0.53 KiB
dist/assets/index.06d14ce2.css             0.17 KiB / gzip: 0.14 KiB
dist/assets/polyfills-modern.e9f39d78.js   34.19 KiB / gzip: 14.12 KiB

However, npx vite build does not print the lines that describe what functions are polyfilled. How should I let vite print this information?

Results from API can be logged to the console but cannot be rendered on the UI. Attempting to map results in Uncaught TypeError

I’m trying to get the information from a free api to display on my page. I am building a crypto app with React and I can use console.log(response.data) to see the array, but the second I try to change the console.log to setCoinList(response.data.coins) I get this error:

Uncaught TypeError: coinList.map is not a function

I am using axios and I don’t think the issue is with the get, I can return the info to the console and view it, and I am starting with a blank array, so I don’t know what is wrong here.

Here is the code in question:

function App() {

  const [coinList, setCoinList] = useState([]);

  useEffect(() => {
    const options = {
      method: "GET",
      url: "https://openapiv1.coinstats.app/coins",
      params: { limit: "20" },
      headers: {
        accept: "application/json",
        "X-API-KEY": MYAPIKEYHERE,
      },
    };

    axios
      .request(options)
      .then((response) => {
        setCoinList(response.data.coins);
      })
      .catch((error) => {
        console.error(error);
      });
  }, []);

  return (

<div className="container mx-auto mt-8">
        {coinList.map((coin) => {
          return (
            <Coin
              key={coin.rank}
              name={coin.name}
              icon={coin.icon}
              symbol={coin.symbol}
              volume={coin.volume}
              price={coin.price}
            />
          );
        })}
      </div>
    </>
  );
}

The syntax appears correct because my editor isn’t throwing an error over the syntax, but for whatever reason the values won’t load. The Coin component also isn’t throwing any errors. The values for the API appear correct Is it possible map doesn’t have anything to map because the data isn’t loaded yet? How do I ensure I get this data first? Any help here would be greatly appreciated.

Please tell me the reasons of using Redux for authentication in a React App, while we already had localStorage

I tried to implement authentication using Redux but I don’t know if it’s necessary while we already had localStorage to use. If we should use Redux, what user information do we store in Redux store and what information do we store in localStorage. What would happen if we don’t use Redux in the long run?
Also is my Redux implementation for login correct ?


const backendApiUrl = 'YOUR_BACKEND_API_URL';

const initialState = {
    loading: false,
    userInfo: {
        username: null,
        email: null,
        fullname: null
    }, // for user object
    userToken: null, // for storing the JWT
    error: null,
    success: false, // for monitoring the registration process.
    isAuthorized: false
}

export const login = createAsyncThunk('auth/login', async (credentials, thunkAPI) => {
    const response = await fetch(`${backendApiUrl}/login`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(credentials),
    });
    const data = await response.json();
    return data;
});

export const authSlice = createSlice({
    name: 'auth',
    initialState,
    reducers: {
        // login: state => {
        //     state.isAuthorized = true


        // },
        // logout: state => { state.isAuthorized = false }
    },
    extraReducers: (builder) => {
        builder
            .addCase(login.fulfilled, (state, action) => {
                state.isAuthorized = true;
                state.userToken = action.payload.token; // Adjust the property based on your backend response
                localStorage.setItem("userToken", action.payload.token);
            })
            .addCase(login.rejected, (state, action) => {
                state.isAuthorized = false;
                state.error = action.payload ? action.payload.error : 'An error occurred';
            })
            .addCase(login.pending, (state) => {
                state.loading = true;
            });
    },
})
// export const { login } = authSlice.actions
export default authSlice.reducer````

Trying to get the current time in JavaScript

const hours = now.getHours();
Console.log(hours);

These set of code is giving me…

Uncaught ReferenceError: now is not
Defined

Note: This is a JavaScript code

I try to use w3school as reference and Google to check the built-in function for time in JavaScript, still I it the same sa now.getHours(); but didn’t run

Is there a way to export content from a node script to a “website” JS script?

I am trying to get the content of a file locally to the front page, and I am using fs using node to read the file, then trying to export the data to the main js file.

Node script

const fs = require('fs')

fs.readFile('damien2134_vs_ryan12030_2024.02.18.pgn', 'utf8', (err, data) => {
    if (err) {console.error(err); return}
    module.exports = {data}
})

Main script (for the website):

const {data} = require('./index.js')

const body = document.body

var p = document.createElement('p')
p.innerText = data

body.append(p)

When tried, it says require is not a function

Trouble Importing File into Premiere Timeline via javascript

I’m trying to make an extension for Premiere Pro that allows me to import sound effects at the current playheads position with an assigned keybind for that sound effect. I’m having trouble importing the sound effect at the playhead. The sound effect is being imported into the project but is not being placed in the timeline. Here is the current code I have.The log is showing the playheads position is accurately being found but then the file just gets imported, not placed into the timeline at the playheads position. Current Extend Script code

I’ll sometimes get a popup saying the file could not be imported as a clip but that’s not true since the file IS being imported properly.

How to detect unused CSS and JS on a multipage website for free?

on a multi-page website, how can I identify unused CSS and JS files? Yes, I am aware that Google DevTools Coverage can be used for this purpose, but my website has a large number of pages, and Coverage only shows the unused code for the page I am currently on. I haven’t been able to find a free and fully effective resource for this. And my CSS codes are over 10000 lines of codes so it is impossible to search for.

Do you have a free resource that you have used and obtained accurate results for identifying unused CSS and JS?

How to add Firebase Appcheck to a react-native app using javascript SDK

I am currently building an app, and I want to add Firebase Appcheck to this app, however I want to maintain the ability to use expo go. I have seen on the firebase documentation that adding a custom attestation provider is possible for the JavaScript SDK, however I don’t really know how this may look. Is there a way to implement this with a recaptcha or other provider using a custom function or would I have to do the attestation myself?

Screenshot of firebase documentation stating that a custom provider can be used

I have tried to implement it directly using the same code as you would for a web app(which I have it working within) so I expected this to just work:

app = initializeApp(firebaseConfig);
initializeAppCheck(app, {
    provider: new ReCaptchaV3Provider("site key"),
    isTokenAutoRefreshEnabled: true, // Set to true to allow auto-refresh.
});

This stopped the app from ever bundling when trying to use expo go. I have also tried a different method which I found suggested, which is probably just a change in syntax:

firebase.initializeApp(firebaseConfig);
const appCheck = firebase.appCheck();
appCheck.activate(
    new ReCaptchaV3Provider("site key"),
    (isTokenAutoRefreshEnabled = true)
);

This is what lead me to dig into the documentation to find that this wasn’t natively supported with the JavaScript SDK. My question is what is the best route to proceed to add appcheck to my react-native app and help protect my firebase project?

A few things to clarify is that I have other firebase features working on the app using the javascript SDK and I am not the only person working on the app so the benefits of using expo go are huge to us to allow fast prototyping so we want to avoid react-native-firebase if possible.

getting information from API to log to the console but not display on page

I’m trying to get the information from a free api to display on my page. I am building a crypto app with React and I can use console.log(response.data) to see the array, but the second I try to change the console.log to setCoinList(response.data.coins) I get this error:

Uncaught TypeError: coinList.map is not a function

I am using axios and I don’t think the issue is with the get, I can return the info to the console and view it, it is just the map method. I don’t even know how to approach this.

Here is the code in question:

useEffect(() => {
    const options = {
      method: "GET",
      url: "https://openapiv1.coinstats.app/coins",
      params: { limit: "20" },
      headers: {
        accept: "application/json",
        "X-API-KEY": "API KEY GOES HERE, key intentionally hidden",
      },
    };

    axios
      .request(options)
      .then((response) => {
        setCoinList(response.data.coins);
      })
      .catch((error) => {
        console.error(error);
      });
  }, []);

&&

<div className="container mx-auto mt-8">
        {coinList.map((coin) => {
          return (
            <Coin
              key={coin.rank}
              name={coin.name}
              icon={coin.icon}
              symbol={coin.symbol}
              volume={coin.volume}
              rank={coin.rank}
              price={coin.price}
            />
          );
        })}
      </div>

The syntax appears correct because my editor isn’t throwing an error over the syntax, but for whatever reason the values won’t load. The Coin component also isn’t throwing any errors. Is it possible map doesn’t have anything to map because the data isn’t loaded yet? How do I ensure I get this data first? Any help here would be greatly appreciated.

Echarts – properly optimise plotting hundreds/thousands series in 2D scatter/line chart

I am trying to plot a large data set containing hundreds/thousands of series with Echarts, but the resulting plot is very slow and difficult to work with.

Here is an example code that you can try in Echarts webpage.


// Generate random series

var series_array = [];

for (let i = 1; i<1000; i++){

  let data = [1,2,3,4,5,6,7].map(function(x) { return x * Math.random(); });
  
  let serie = {
    name: 'Serie'+i,
    type: 'line',
    data: data
  };
  
  series_array.push(serie);
}

// Chart options

option = {
  title: {
    text: 'Stacked Line'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine']
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },
  toolbox: {
    feature: {
      saveAsImage: {}
    }
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
    dataZoom: [
    {
      type: 'inside',
      start: 0,
      end: 100
    },
    {
      start: 0,
      end: 100
    }
  ],
  series: series_array
};

I tried using large and progressive, but they seem to work on single series and not on all series plotted.

How should I properly improve the performance of this type of chart?

React weird text animation that I can only recreate on my phone (not in inspect element’s phone mode)

enter image description here

I have a component that I made that animates a single word, by cycling through a list of words and applied an animation to them.

Not only does it do this, it also dynamically sets the width of the word according to the width of the new word, and moves the adjacent words with an animation too. It’s easier to look at the gif of it above.

The weird behavior is the “Draft Pick” keeps being put into 2 lines instead of 1, which results in it being weird looking.

here is where it’s implemented

<h1 className="text-white font-semibold text-[35px] lg:text-[50px] text-center title-shadow max-w-3xl">
        A Stats Gameplan <br/>
        to Help You Win More {" "} <br />
        <TextSwap
          strings={["ARAM", "Ranked", "Draft Pick", "Blind Pick"]}
          animationType="slideDown"
          className="text-winions-orange text-nowrap"
        />
        {" "}Games
        </h1>

here is the animation component

import React, { useEffect, useState, useRef } from "react";
import "./styles.css";

const buildAnimationStyle = (type, durationMs, widthTransitionDurationMs) => ({
  display: "inline-block",
  animation: `${type} ${durationMs / 1000}s`,
  "animation-fill-mode": "forwards",
  transition: `width ${widthTransitionDurationMs / 1000}s ease`, // Convert milliseconds to seconds for CSS
});

// Additional style for the hidden span used to measure text width
const measureStyle = {
  visibility: "hidden",
  position: "absolute",
  whiteSpace: "nowrap",
  top: "-9999px",
  left: "-9999px",
};

export const TextSwap = ({
  strings,
  interval = 2000, // Default interval in milliseconds
  animationType = "fade",
  animationDuration = 2100, // Default duration in milliseconds
  className = "",
  widthTransitionDuration = 500, // Default width transition duration in milliseconds
}) => {
  const animationStyle = buildAnimationStyle(animationType, animationDuration, widthTransitionDuration);
  const [currString, setCurrString] = useState(strings[0]);
  const [containerWidth, setContainerWidth] = useState("auto");
  const measureRef = useRef(null);

  // Measure and update width based on the current string
  useEffect(() => {
    if (measureRef.current) {
      setContainerWidth(`${measureRef.current.offsetWidth}px`);
    }
    
    const timer = setInterval(() => {
      const currIndex = strings.indexOf(currString);
      const nextIndex = currIndex < strings.length - 1 ? currIndex + 1 : 0;
      setCurrString(strings[nextIndex]);
    }, interval);

    return () => {
      clearInterval(timer);
    };
  }, [currString, strings, interval]);

  return (
    <>
      <div
        key={currString}
        style={{ ...animationStyle, width: containerWidth }}
        className={className}
      >
        {currString}
      </div>
      {/* Invisible span to measure text width */}
      <span ref={measureRef} style={measureStyle}>
        {currString}
      </span>
    </>
  );
};

also what’s weird, is that I cannot recreate this issue through my desktop browser (at any resolution), but when I push the changes to a testing environment (so that I can see it on my actual phone) the issue is there (??)

I need help making the “Draft Pick” stay one line only!