My canvas is being overwritten by another canvas for barcode

I have a function that draws a canvas then draws another canvas inside for a barcode. It seems to be overwriting it.

function generateCard(userId, users, cardIMG){
    if (canvas.getContext) {
        const ctx = canvas.getContext("2d");
        ctx.fillStyle = "#FFFFFF"; // white background color
    ctx.fillRect(0, 0, canvas.width, canvas.height);
        //blue
    ctx.beginPath();
    ctx.moveTo(0, 0);
        ctx.lineTo(1000, 0);
    ctx.lineTo(1000,60);
    ctx.lineTo(500,60);
    ctx.lineTo(350,180);
    ctx.lineTo(30,180);
    ctx.lineTo(0,200);
    ctx.lineTo(0,0);
    ctx.stroke();
        ctx.fillStyle = "#002D62";
    ctx.fill();
        //yellow right 
    ctx.beginPath();
    ctx.moveTo(1000, 60);
    ctx.lineTo(1000,80);
    ctx.lineTo(500, 80);
    ctx.lineTo(530, 60);
    ctx.lineTo(1000, 60);
    ctx.stroke();
    ctx.fillStyle = "#FFFD37";
    ctx.fill();
    //yellow left
    ctx.beginPath();
    ctx.moveTo(0, 200);
    ctx.lineTo(300, 200);
    ctx.lineTo(330, 180);
    ctx.lineTo(30, 180);
    ctx.lineTo(0, 200);
    ctx.stroke();
    ctx.fillStyle = "#FFFD37";
    ctx.fill();
    //profile border
    ctx.beginPath();
    ctx.moveTo(50, 244);
    ctx.lineTo(350, 244);
    ctx.lineTo(350, 545);
    ctx.lineTo(50, 545);
        ctx.lineTo(50, 240);
    ctx.strokeStyle = "#002D62";
    ctx.lineWidth = 8;
    ctx.stroke();
    //underline
    ctx.beginPath();
    ctx.moveTo(600, 225);
    ctx.lineTo(790, 225);
    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;
    ctx.stroke();
    
    ctx.font = "bold 18px Arial";
    ctx.fillStyle = "black";
    ctx.fillText("WENCESLAO Q. VINZONS MEMORIAL LIBRARY",500,120);
    ctx.font = "italic 18px Arial";
    ctx.fillText("CAMARINES NORTE PROVINCIAL LIBRARY",525,145);
    ctx.font = "italic 13px Arial";
    ctx.fillText("DAET, CAMARINES NORTE",630,170);
    ctx.font = "bold 25px Arial";
    ctx.fillText("LIBRARY CARD",600,220);
    ctx.font = "bold 18px Arial";
    ctx.fillText("NAME:",460,270);
    ctx.fillText("ADDRESS:",460,310);
    ctx.fillText("DATE OF BIRTH:",460,350);
    ctx.fillText("DATE ISSUED:",460,390);
    ctx.fillText("VALID UNTIL:",460,430);

The data comes from firebase, even the userId that the barcode uses.

    ctx.fillText(users.firstname + " " + users.lastname,640,270);
    ctx.fillText(users.street + ", " + users.cityProvince,640,310);
    ctx.fillText(users.birthmonth + "-" + users.birthday + "-" + users.birthyear,640,350);
    ctx.fillText(users.issued,640,390);
    ctx.fillText(users.exp,640,430);
    
    let liblogo = new Image();
    let camnorte = new Image();
    let profile = new Image();

It seems to load the canvas first, before being overwritten. I tried making a new canvas inside but it didn’t show so I did this one.

    liblogo.src = "/Library User Creation/res/liblogotransparent.png";
    camnorte.src = "/Library User Creation/res/camnortelogo.png";
    profile.src = "/Library User Creation/res/profilewithbg.png";
    profile.src = cardIMG;
    Promise.all([liblogo, camnorte, profile].map(image => new Promise((resolve, reject) =>{
            image.onload = resolve;
            image.onerror = reject;
        })))
        .then(() => {
            ctx.drawImage(liblogo, 150, 25, 130, 130);
            ctx.drawImage(camnorte, 40, 40, 100, 100);
            ctx.drawImage(profile, 50, 245, 300, 300);
            JsBarcode(canvas, userId, {
                format: "CODE39",
                width: 2,
                height: 80,
                displayValue: false
            });
        })
    .catch(error => console.error("Error loading images:", error));
}

}

Implementing video conference web app with sign language translator

We built this web app using T3 stack. We trained keras model and converted it to model.json using tensorflowJS and hosted it in cloud, the python model detects perfectly but when it is converted and integrated to the web app it gives only one label (we have trained the model for with 6 signs). I think the problem is in the conversion (we used tensorflowJs to convert it). can someone with good knowledge of tensorflow and tfJS help us.

code

OR

option 2:
Iam panning to rebuid it agin with react and flask.
Model will run in backend, the keypoints extracted by mediapipe holistic should be continuously sent to backend REST api. Is it OK do it?

because in first case, since the model runs in browser the latency will be less.

We tried to host the model.json and prdict the sign language.
When we tested the model in the jupyter notebook (before converting ) it gave proper result.
But after we converted from python to js and integrated to T3 app it preditcs only one sign and gives the same answer for all signs.

Reassigning a global variable in JavaScript using an event listener

Apologies but I’m fairly new to JS – i’m attempting to assign “humanChoice” using event listeners and then use that value in the function playRound. However, when I print it to the log, the value is returning as undefined although I’m attempting to assign it. Any help would be appreciated. Thanks.

let humanChoice

rock.addEventListener('click', () => {
    humanChoice = "rock"
    playRound()
});

function playRound(humanChoice, computerChoice) {

    if (humanChoice === computerChoice) {
        console.log("It's a tie! There is no winner this round.")
    } else if (humanChoice === "rock" && computerChoice === "paper") {
        computerScore++
        console.log("You lose! Your score is " + humanScore + " and the computer's score is " + computerScore + ".")
    } else if (humanChoice === "rock" && computerChoice === "scissors") {
        humanScore++
        console.log("You win! Your score is " + humanScore + " and the computer's score is " + computerScore + ".")
    } else if (humanChoice === "paper" && computerChoice === "rock") {
        humanScore++
        console.log("You win! Your score is " + humanScore + " and the computer's score is " + computerScore + ".")
    } else if (humanChoice === "paper" && computerChoice === "scissors") {
        computerScore++
        console.log("You lose! Your score is " + humanScore + " and the computer's score is " + computerScore + ".")
    } else if (humanChoice === "scissors" && computerChoice === "paper") {
        humanScore++
        console.log("You win! Your score is " + humanScore + " and the computer's score is " + computerScore + ".")
    } else if (humanChoice === "scissors" && computerChoice === "rock") {
        computerScore++
        console.log("You lose! Your score is " + humanScore + " and the computer's score is " + computerScore + ".")
    }
}

I would expect humanChoice to be reassigned to “rock”, and allow me to pass it in to playRound. However, it returns undefined.

Error: (0 , react__WEBPACK_IMPORTED_MODULE_1__.useActionState) is not a function or its return value is not iterable

I am following the example for useActionState found here. I am using nextjs

When I run the example, I get:
Error: (0 , react__WEBPACK_IMPORTED_MODULE_1__.useActionState) is not a function or its return value is not iterable

My package.json looks like:

{
  "name": "my-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "db:migrate": "TS_NODE_COMPILER_OPTIONS='{ "module": "commonjs" }' knex migrate:latest",
    "db:migrate:undo": "TS_NODE_COMPILER_OPTIONS='{ "module": "commonjs" }' knex migrate:down",
    "db:migrate:make": "TS_NODE_COMPILER_OPTIONS='{ "module": "commonjs" }' knex migrate:make"
  },
  "dependencies": {
    "@prisma/client": "^5.13.0",
    "antd": "^5.16.1",
    "classnames": "2.3.1",
    "dotenv": "^16.4.5",
    "faker": "^6.6.6",
    "knex": "^3.1.0",
    "next": "14.1.4",
    "pg": "^8.11.5",
    "react": "canary",
    "react-dom": "canary",
    "react-scripts": "^5.0.0"
  },
  "devDependencies": {
    "@faker-js/faker": "^8.4.1",
    "@types/node": "20.12.2",
    "@types/react": "18.3.1",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.4.19",
    "eslint": "^8",
    "eslint-config-next": "14.1.4",
    "postcss": "^8.4.38",
    "prisma": "^5.13.0",
    "tailwindcss": "^3.4.3",
    "typescript": "4.9.5"
  }
}

ReactJS function takes a double of click to be triggered

I have 2 functions, function uploadFile uploads the file image to firebase and then store the returned url through setState, and function saveTeam which send a request to /new-team-member with payload including the returned url

const uploadFile = async () => {
  const imageRef = storageRef(storage, `images/${UniqueComponentId()}`);
  uploadBytes(imageRef, team.image)
    .then((snapshot) => {
      getDownloadURL(snapshot.ref)
        .then((url) => {
          setTeam({ ...team, url: url || team.image });
        })
        .catch((error) => {
          console.log(error.message);
        });
    })
    .catch((error) => {
      console.log(error.message);
    });
};

const saveTeam = async () => {
  setSubmitted(true);
  let _teams = [...teams];
  let _team = { ...team };
  if (team.id) {
    await fetch('https://bunaq-api.vercel.app/api/edit-team-member', {
      method: 'PUT',
      body: JSON.stringify(team),
      headers: { 'Content-Type': 'application/json' },
    });
    const index = findIndexById(team.id);
    _teams[index] = _team;
    toast.current.show({
      severity: 'success',
      summary: 'Successful',
      detail: t('adminTeamPage.new.toastUpdated'),
      life: 5000,
    });
  } else {
    fetch('https://bunaq-api.vercel.app/api/new-team-member', {
      method: 'POST',
      body: JSON.stringify(team),
      headers: { 'Content-Type': 'application/json' },
    });
    _teams.unshift(_team);
    // location.reload();
    toast.current.show({
      severity: 'success',
      summary: 'Successful',
      detail: t('adminTeamPage.new.toastCreated'),
      life: 5000,
    });
  }
  setTeams(_teams);
  setTeamDialog(false);
  setTeam(emptyTeam);
};

const saveTeamMain = async () => {
  await uploadFile();
  saveTeam();
};

<button onClick={saveTeamMain}>Save</button>;

But when i click Save it doesn’t do anything for the first time, and then triggers the function on the second click, why is that happening ?

Can it lead to tooth decay?

هل يمكن أن تؤدي لتسوس الأسنان؟

نعم، يمكن أن تؤدي سوء العناية بالأسنان إلى تسوس الأسنان. عندما لا يتم الاهتمام بنظافة الأسنان بشكل جيد،
يتراكم البلاك (الطبقة اللاصقة المكونة من البكتيريا والفضلات الغذائية) على سطح الأسنان. تتفاعل البكتيريا في البلاك مع السكريات الموجودة في الطعام والمشروبات لإنتاج حمض يهاجم طبقة المينا (المادة الصلبة الخارجية للأسنان)، مما يؤدي إلى تكون تسوس الأسنان.

لتجنب تسوس الأسنان، ينصح باتباع الإجراءات التالية:

  • تنظيف الأسنان بفرشاة الأسنان واستخدام خيط الأسنان يوميًا لإزالة البلاك والفضلات الغذائية.
  • تقليل تناول السكريات والمشروبات الغازية السكرية.
  • زيارة طبيب الأسنان بانتظام لفحص الأسنان وإجراء تنظيف دوري وعلاج أي مشاكل مبكرًا.

معجون اسنان

مصادر:

  • Mayo Clinic: “Cavities and tooth decay – Symptoms and causes”
  • موقع الصحة العالمية: “تسوس الأسنان”
  • موقع الجمعية الأمريكية لأطباء الأسنان: “تسوس الأسنان والوقاية منه”

API OU Banco de Dados [closed]

Estou com uma dúvida seria.

Desenvolvi um site para uma academia, onde a pessoa tem a opção de fazer uma “MATRICULA” , mas não estou sabendo a forma correta de armazenar estes dados, estou em dúvida entre uma API ou um BANCO DE DADOS em Mysql.

Se alguém poder me pontuar o motivo para usar a opção a qual sugerir.

Não ententei, apenas avaliando as possibilidades.

Why is it when throwing custom error, my error type returns object

I have a nextjs app sample that sends a request but when trying to catch an error and checking if its my custom type it returns false, and when checking its err.name returns object.

page.tsx

'use client'

...some code
handleSumbit() {

  try {
    const res = await create(values);
    console.log(res)
  } catch (err: unknown) {
   console.log(typeof err, err instanceof ResponseError) <--- returns   object, false

   if(err instanceof ResponseError) {
     if(err.reponse.status === 400) {
      // do something with the bad request here
     }
   }

   }

}

...some code

CREATE method Requests.ts

'use server'

 export async function create(data: DATA) {

   const res = await fetch(`${BASE_URL}/magic`, {
        method: "POST",
        headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${acc_tok?.value}`,
        },
        body: JSON.stringify(data),
   });

  if (!res.ok) throw new ResponseError('Bad fetch response', res) <---- THE TYPE IM EXPECTING

  return await res.json();

 }

responseError Class

  export class ResponseError extends Error {
  response: Response;
  constructor(message: string, res: Response) {

    super(message);
    this.name = this.constructor.name
    this.response = res
  }
}

I’m not sure if this is the behavior from nextjs but when I tried this in just react (No framework) this works fine, also tried it on the backend this works too. I mean when throwing a custom error I can still verify the type is not changing.

Discord.js Giveaway command [closed]

So in my code everything works, the only thing is that if the bot is crashed/restarted the giveaway does not work anymore, so like it does not do anything in the code anymore. If you can try to use node-cron that’s fine too but I can’t figure it out.

import { giveaway, giveaway_endDate } from "../../data/mongodb.js";
import ms from "ms";
import { v4 as uuidv4 } from 'uuid';

export const data = {
    name: "giveawaycreate",
    type: 1,
    description: "Creates a new giveaway",
    options: [
        {
            type: 3, // STRING Type
            name: "name",
            description: "Title of giveaway",
            required: true
        },
        {
            type: 4, // INTEGER Type
            name: "winners",
            description: "Number of winners",
            required: true
        },
        {
            type: 3, // STRING Type
            name: "duration",
            description: "Duration of the giveaway",
            required: true
        }
    ],
    dm_permission: false,
    default_member_permissions: 0
};

export async function execute(interaction, client) {
    await interaction.deferReply({ ephemeral: true });

    const title = interaction.options.getString("name", true);
    const winnerCount = interaction.options.getInteger("winners", true);
    const durationOption = interaction.options.getString("duration", true);
    const msDuration = await ms(durationOption);

    const endDate = new Date(Date.now() + msDuration);
    const formattedEndDate = `${endDate.getMonth() + 1}/${endDate.getDate()}/${endDate.getFullYear()}`;
    const unix = Math.floor(endDate / 1000);
    const remainingTime = `<t:${unix}:R>`;
    const giveawayId = uuidv4();

    const embed = {
        color: client.settings.color,
        footer: { text: `${winnerCount} winners | Ends at u2022 ${formattedEndDate}` },
        url: "https://www.google.com/search?q=hello+world",
        image: { url: `https://thumbs2.imgbox.com/a2/41/pNr8rADZ_t.png` },
        description: `### ${title}`,
        fields: [
            { name: "Time Remaining", value: `${remainingTime}`, inline: true },
            { name: "Hosted by", value: `${interaction.user}`, inline: true },
        ],
    };

    const hiddenEmbed = {
        description: giveawayId,
        url: "https://www.google.com/search?q=hello+world"
    };

    const giveaway_enter = {
        type: 1,
        components: [{
            type: 2,
            label: `Enter`,
            emoji: "<:tada:1230682264384311357>",
            style: 3,
            custom_id: `giveaway_enter`,
        }, {
            type: 2,
            label: `Leave`,
            style: 2,
            custom_id: `giveaway_leave`,
        }]
    };

    const originalReply = await interaction.channel?.send({ embeds: , ephemeral: false, components: [giveaway_enter] });
    await interaction.deleteReply();

    const logChannel = interaction.guild.channels.cache.get(client.settings.hrLogChannelId);
    if (!logChannel) {
        return interaction.reply({
            content: "CONFIGURATION ERROR: Check Log Channel ID!",
            ephemeral: true,
        });
    }

    const logEmbed = {
        title: "SFRA Command Logging",
        description: `${interaction.user} used **giveaway** command in <#${interaction.channel.id}>.`,
        fields: [
            { name: "Moderator", value: `${interaction.user}`, inline: false },
            { name: "Name", value: `${title}`, inline: false },
            { name: "Winners", value: `${winnerCount}`, inline: false },
            { name: "Time Remaining", value: `${remainingTime}`, inline: false },
        ],
        color: client.settings.color,
        footer: { text: `${interaction.guild.name}`, icon_url: interaction.guild.iconURL() || undefined },
    };

    logChannel.send({ embeds: [logEmbed], ephemeral: false });

    const giveawayEndDateSave = new giveaway_endDate({
        endDate: endDate,
    });
    await giveawayEndDateSave.save();

    const interval = setInterval(async () => {
        const currentDate = new Date();
        if (currentDate >= endDate) {
            clearInterval(interval);

            const winners = await selectWinnersFromDatabase(giveawayId, winnerCount);

            embed.fields.push({ name: "Winners", value: winners.map(winner => `<@${winner}>`).join('n'), inline: true });

            await originalReply.edit({ embeds: , components: [] });

            await giveaway_endDate.deleteMany({ endDate: endDate });
            await giveaway.deleteMany({ giveawayId: giveawayId });

            const winnerIds = winners.map(winner => `<@${winner}>`).join(' ');
            await interaction.channel.send(`Congratulations ${winnerIds}, you won ${title}!`);

            await clearGiveawayData(giveawayId);
        }
    }, 60000);
}

async function selectWinnersFromDatabase(giveawayId, winnerCount) {
    const participants = await giveaway.find({ giveawayId });

    shuffleArray(participants);

    return participants.slice(0, winnerCount).map(participant => participant.userId);
}

async function clearGiveawayData(giveawayId) {
    await giveaway.deleteMany({ giveawayId });
}

function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

Please ignore this part it wants me to put more things than code so i am going to just put a lot of “g’s”.
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg

Await dispatch has no effect

I have to dispatch the action that makes the request to the API to create a user. The problem is that I can’t put an awiat to the dispatch because it has no effect. I am using redux toolkit for the state. What I want to achieve is that the navigate is executed only if the dispatch is carried out successfully. I leave you my code

  const onSubmit = async (data) =>{
    const userInfo = {
      username:data?.username,
      email:data?.email,
      phone:data?.phoneNumber,
      password:data?.password,
    }
    try {
      dispatch(signUp(userInfo))
      
        navigate("/signin"); // deberia ejecutarse solo si el dispatch es exitoso
  
    } catch (error) {
      console.log(error);
    }
  }

async thunk

import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
export const signUp = createAsyncThunk(
    "type/postData",
    async (data, thunkAPI) => {
      try {
        const response = await axios.post("http://localhost:4001/auth/register", data);
        // Si deseas obtener algo de vuelta
        return response.data;
      } catch (error) {
        if (error.response && error.response.data && error.response.data.error) {
          return thunkAPI.rejectWithValue(error.response.data.error);
        } else {
          throw new Error('Error fetching user applications: ' + error.message);
        }
      }
    }
);

the slice:

import { createSlice } from "@reduxjs/toolkit";
import { signUp } from "../actions/userActions";

const initialState = {
    userInfo:{},
    loading: false,
    error: null,
}

export const userSlice = createSlice({
    name: 'user', // Corregí el nombre del slice
    initialState,
    reducers: {
        // Aquí puedes agregar tus propias acciones si es necesario
    },
    extraReducers: (builder) => {
        builder
            .addCase(signUp.pending, (state) => {
                state.loading = true;
                state.error = null;
            })
            .addCase(signUp.fulfilled, (state) => {
                state.loading = false;
                state.error = null;
            })
            .addCase(signUp.rejected, (state, action) => {
                console.log(action);
                state.loading = false;
                state.error = action.payload;
            });
    },
});

export default userSlice.reducer;

I tried to use the await before the dispatch and it has no effect, also execute the navigate() with a .then after the dispatch and I have no results either

Why is my JS event handler not working in SVG?

I am currently making a graphing calculator in C++. I wanted to make multiple versions of said graphing calculator. This first attempt uses SVG and JS to create graphs.

When I create the file and use the SVG file I wish to display the point of the graph (where a user clicks). However, my method to display the coordinates is not working. I click the graph, and nothing happens.

Code:

struct Point {
    double x;
    double y;
};

using Function = long double (*)(long double);

double evaluate(Function func, double x) {
    return static_cast<double>(func(x));
}

void plotGraph(Function func, double minX, double maxX, double minY, double maxY, double stepSize, int SVG_SIZE, const string& hexLineColor) {
    // Calculate number of points to plot
    int numPoints = static_cast<int>((maxX - minX) / stepSize) + 1;

    // Vector to store points
    vector<Point> points(numPoints);

    // Evaluate function at each step and store points
    for (int i = 0; i < numPoints; ++i) {
        double x = minX + i * stepSize;
        double y = evaluate(func, x);
        // Check if y is NaN, if so, skip this point
        if (!isnan(y)) {
            points[i] = {x, y};
        } else {
            // Set x-coordinate of the skipped point to NaN so it's not drawn
            points[i] = {NAN, NAN};
        }
    }

    // Normalize points to fit in the specified range
    double xRange = maxX - minX;
    double yRange = maxY - minY;

    for (auto& point : points) {
        if (!std::isnan(point.x)) {
            point.x = (point.x - minX) * SVG_SIZE / xRange;
            point.y = (point.y - minY) * SVG_SIZE / yRange;
        }
    }

    // Calculate the x-position of the y-axis
    double yAxisXPos = -minX * SVG_SIZE / xRange;
    if (minX <= 0 && maxX >= 0) {
        yAxisXPos = -minX / (maxX - minX) * SVG_SIZE;
    } else if (minX > 0) {
        yAxisXPos = 0;
    } else {
        yAxisXPos = SVG_SIZE;
    }

    // Calculate the y-position of the x-axis
    double xAxisYPos;
    if (minY <= 0 && maxY >= 0) {
        xAxisYPos = maxY / (maxY - minY) * SVG_SIZE;
    } else if (minY > 0) {
        xAxisYPos = SVG_SIZE;
    } else {
        xAxisYPos = 0;
    }

    // Open SVG file for writing
    ofstream svgFile("graph.svg");

    // SVG header
    svgFile << "<svg width="" << SVG_SIZE << "" height="" << SVG_SIZE << "" xmlns="http://www.w3.org/2000/svg">" << std::endl;

    // Draw x-axis
    svgFile << "<line x1="" << yAxisXPos << "" y1="0" x2="" << yAxisXPos << "" y2="" << SVG_SIZE << "" style="stroke:black;stroke-width:1"/>" << std::endl;
    // Draw y-axis
    svgFile << "<line x1="0" y1="" << xAxisYPos << "" x2="" << SVG_SIZE << "" y2="" << xAxisYPos << "" style="stroke:black;stroke-width:1"/>" << std::endl;

    // Plot points and lines
    for (int i = 1; i < numPoints; ++i) {
        // Check if both x-coordinates are not NaN
        if (!isnan(points[i - 1].x) && !isnan(points[i].x)) {
            // Check if both y-coordinates are not NaN
            if (!isnan(points[i - 1].y) && !isnan(points[i].y)) {
                // Draw line between two points
                svgFile << "<line x1="" << points[i - 1].x << "" y1="" << SVG_SIZE - points[i - 1].y << "" "
                        << "x2="" << points[i].x << "" y2="" << SVG_SIZE - points[i].y << "" "
                        << "style="stroke:#" << hexLineColor << ";stroke-width:2"/>" << std::endl;
            }
        }
    }

    // Add event handler for clicking on points
    svgFile << "<script><![CDATA[" << std::endl;
    svgFile << "function showCoordinates(evt) {" << std::endl;
    svgFile << "    var svg = evt.target.ownerDocument;" << std::endl;
    svgFile << "    var point = svg.createSVGPoint();" << std::endl;
    svgFile << "    point.x = evt.clientX;" << std::endl;
    svgFile << "    point.y = evt.clientY;" << std::endl;
    svgFile << "    var svgPoint = point.matrixTransform(svg.getScreenCTM().inverse());" << std::endl;
    svgFile << "    var textElement = document.createElementNS('http://www.w3.org/2000/svg', 'text');" << std::endl;
    svgFile << "    textElement.setAttribute('x', svgPoint.x);" << std::endl;
    svgFile << "    textElement.setAttribute('y', svgPoint.y);" << std::endl;
    svgFile << "    textElement.setAttribute('fill', 'black');" << std::endl;
    svgFile << "    textElement.textContent = '(' + svgPoint.x.toFixed(2) + ', ' + svgPoint.y.toFixed(2) + ')';" << std::endl;
    svgFile << "    svg.appendChild(textElement);" << std::endl; // Append to the SVG root
    svgFile << "}" << std::endl;
    svgFile << "]]></script>" << std::endl;

    // Draw a transparent rectangle to capture clicks
    svgFile << "<rect width="" << SVG_SIZE << "" height="" << SVG_SIZE << "" fill="transparent" onclick="showCoordinates(evt)"/>" << std::endl;

    // Close SVG tag
    svgFile << "</svg>";

    // Close the file
    svgFile.close();

    cout << "Graph created in graph.svg" << endl;
}

I have tried changing the syntax a few times and I have completely changed my approach once (caused an error, so I won’t go into detail)

JavaScript userscripts: Checklist for making sure userscript doesn’t have security loopholes? [closed]

I am not expecting a definitive and complete fool-proof list, since security is an extremely complex issue, so that would not be realistic, certainly not in a format like this.

I am also not looking for a list of attacks: If anything, a list of things to avoid attacks.

I am aware of authoritative sources such as Mozilla’s Types of attacks and others, including entire libraries on the topic. However, those are deep descriptions of types of attacks, but certainly not focused on mere userscripts for e.g. Tampermonkey, and also not on practical tips, which is what I am specifically aiming to. Or at least I have not been able to find something like that.

One example: In this answer, @Bergi says: ...beware that it is possible for hostile webmasters to follow unsafeWindow usage back to the script's context and thus gain elevated privileges to pwn you with.

I am looking for a humble practical set of at least some top priority guidelines to be able to say “my script does not have a security loophole“. I suppose someone saying so would have gone through a reasonable set of well-known practical things. Well, I would imagine so.

So, when coding a userscript, for the likes of Tampermonkey (or other “monkeys”): what are the minimum (at least some) obvious things that I should go through, that my code should -or should not- be doing to avoid “security loopholes” (for example a webmaster attacking my script) without having to complete a Phd thesis to prove it?

Trying to set a form’s file input.value = null inside addEventListener

I’m trying to get rid of some errors in the web console of my internal site. This JS is not meant to serve as proper form validation or be security minded, it’s only done to apply a quick fix on the frontend of a completely internal site to limit the upload size and clear the form’s file input if the size exceeds 29M. I’m just curious of how to clear the input without having these errors.

...
                <input id="myFile" class="form-control" type="file" name="attachment" placeholder="Attachment"/>
        </form>
    </body>
...
...
    var myFile = document.getElementById('myFile');
    myFile.addEventListener('change', function() {
        var maxSize = myFile.files[0].size;
        if(maxSize > 29000000) {
            alert("The attachment you've selected with a file size of " + maxSize + " bytes exceeds the maxium size permitted");
            myFile.value = null;
            myFile.dispatchEvent(new Event('change'))
        }
    });
...

In the java console, when a file is selected on input id=”myFile” which is > 29000000 bytes, I get the alert, and the following on the console:

test/:137 Uncaught TypeError: Cannot read properties of undefined (reading 'size')
    at HTMLInputElement.<anonymous> (test/:137:39)
    at HTMLInputElement.<anonymous> (test/:141:20)

Everything technically “works” but it would appear that even though the condition to check for file size is an “if” and not a “while”, clearing the value inside the if block (myFile.value = null) seems to be the cause of the error. I am NOT a java-script person. What’s the correct way to check for properties on a form element and nullify that same element?

Thank you!

Google Apps Script methods returning “Proxy”

Google Apps Script is behaving really strangely for me and am wondering if anyone else has ever encountered the same issue and found a fix.

Instead of returning the objects / classes that the methods are supposed to return, they are instead returning “Proxy” objects, as you can see in the below screenshot which is from the debugger in the IDE:

Debugger image

Here is the very simple code I used to generate the example of my issue, with ‘my_url_here’ obviously replaced with the real Google Sheets URL:

function test() {
  
  const ss = SpreadsheetApp.openByUrl('my_url_here');

  Logger.log(ss);
}

I tried converting the “Proxy” to a usable object with Object.values( ) but that did not produce anything useful:

Using Object.values( )

Any assistance will be greatly appreciated!

Thanks

Encrypt AES-GCM in PHP, decrypt in Javascript

I have a message encrypted in PHP like this:

function encode(string $input): string
{
    return base64EncodeSafe(encodeOpenSsl($input));
}

function encodeOpenSsl(string $string): string
{
    if (!defined('CRYPT_KEY') || !defined('CRYPT_CIPHER')) {
        return $string;
    }

    $key = hex2bin(CRYPT_KEY);
    $ivLength = openssl_cipher_iv_length(CRYPT_CIPHER);
    do {
        $iv = openssl_random_pseudo_bytes($ivLength, $cstrong);
    } while (!$iv && !$cstrong);
    $encryptedString = $iv . openssl_encrypt($string, CRYPT_CIPHER, $key, OPENSSL_RAW_DATA, $iv, $tag);

    if (!empty($tag)) {
        $encryptedString .= '||' . $tag;
    }
    return base64_encode($encryptedString . '||' . $tag);
}

function base64EncodeSafe(string $string): string
{
    return str_replace(['/', '+'], ['_', '-'], base64_encode($string));
}

And I need to decrypt it in Javascript. This is my decryption code:

async function decode(input) {
    return await decodeOpenSsl(base64DecodeSafe(input));
}

function base64DecodeSafe(string) {
    return atob(string.replace(/_/g, '/').replace(/-/g, '+'));
}

async function decodeOpenSsl(data) {
    const key = hexStringToByteArray(CRYPT_KEY);
    const parts = atob(data).split('||');
    const ivAndEncrypted = new Uint8Array(parts[0].split('').map(c => c.charCodeAt(0)));
    const tag = new Uint8Array(parts[1].split('').map(c => c.charCodeAt(0)));
    const iv = ivAndEncrypted.slice(0, 12);
    const encrypted = ivAndEncrypted.slice(12);

    const encryptedWithTag = new Uint8Array([...encrypted, ...tag]);

    const cryptoKey = await crypto.subtle.importKey(
        'raw',
        key,
        { name: 'AES-GCM' },
        false,
        ['decrypt']
    );

    const decrypted = await crypto.subtle.decrypt(
        { name: 'AES-GCM', iv: iv, additionalData: new Uint8Array(), tagLength: 128 },
        cryptoKey,
        encryptedWithTag
    );

    return new TextDecoder().decode(decrypted);
}

function hexStringToByteArray(hexString) {
    var result = [];
    while (hexString.length >= 2) {
        result.push(parseInt(hexString.substring(0, 2), 16));
        hexString = hexString.substring(2, hexString.length);
    }
    return new Uint8Array(result);
}

But I keep getting the following:

DOMException [OperationError]: The operation failed for an operation-specific reason
at AESCipherJob.onDone (node:internal/crypto/util:445:19) {
[cause]: [Error: Cipher job failed]

The error doesn’t give much info probably for security reasons, but maybe someone had a problem like this and could help. Thank you.