Node JS - How can I post to an iframe without needing to open the page? I need to act like an API in the background

Viewed 292

So I have a piece of code that automatically changes a .psd image depending on the user inputs.

I am using https://www.photopea.com/ to achieve this using their handy API and scripts.

Note: Photopea has a nice feature that when you enter your url inside the server array, and you call save as a script, it saves the file, posted to your server link you put. This works fine (Only when I have the page opened myself like a normal client. Not without opening the page).

My issue is, I need to be able to make a post request to update the script (to the iframe window), without the client actually opening the page / browser. This is sort like an API. It needs to check an incoming post request for the values entered to change on the .psd, then it needs to automatically do these changes without the user needing to open the page.

Sorta like an api running in the background, checking for incoming connections, then once it has found the post request to our node js, it will run the script to change the .psd layers to suit users values.

What I'm stuck at: When I run the script in a API sorta mode (through post request, not opening the page manually, it shows me this error message here.

This is my html page I need to load without needing the client to open it up:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>PSD Changer</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <style type="text/css">
     input {
     padding:  7px;
     width: 100%;
     margin: 10px 0px 10px 0px;
     }
  </style>
</head>
<body>
<textarea rows="8", style="width:100%;" id="json">
   {
    "files": [ 
    "https://www.photopea.com/#MY_PHOTOPEA_PSD"
],
"resources" : [
],
"environment" : {
},
"server" : {
    "version" : 1,
    "url"     : "https://www.myserver.cc/saveFile.php",
    "formats" : [ "png:true", "jpg:0.5" ]
}
}</textarea>
  <button onclick="updatePlayground()" style="display:block;  font-size:1.2em;" >Update</button>  <br />
  <b>URL:</b>
  <textarea rows="3", style="width:100%;" id="url"></textarea>

  <iframe src="https://www.photopea.com?rnd=44567643" id="pp" style="border:none; width:100%; height:600px;"></iframe> 

  <button onclick="testOurAuto();">Auto Change Text</button>  
  <h2>Run a script</h2>
  <textarea rows="4", style="width:100%;" id="script">app.activeDocument.activeLayer.translate(20,20);</textarea>
  <button onclick="runScript()" style="display:block;  font-size:1.2em;">Run</button> <br />          
  <b>Messages from Photopea</b>
  <pre id="msgs"></pre>
  <hr>
  <div style="background: black; margin-top: 50px; color: white; padding: 100px;">
     <h1>Auto Config Editor</h1>
     <label>Change first name to:</label>
     <input type="text" id="new_first_name" placeholder="Enter new first name for ID here" />
     <br>
     <label>Change last name to:</label>
     <input type="text" id="new_last_name" placeholder="Enter new last name for ID here" />
     <hr>
     <label>Change date of birth to:</label>
     <input type="text" id="new_dob" placeholder="Enter new date of birth - 05.07.1991 for ID here" />
     <br>
     <label>Change city to:</label>
     <input type="text" id="new_city" placeholder="Enter new city for ID here" />
     <br>
     <label>Change expiry date to:</label>
     <input type="text" id="new_expiry_date" placeholder="Enter new expiry date for ID here" />
     <button style="width: 100%; background: black; padding: 30px; color: white;" onclick="testOurAuto('<?=$first_name;?>', '<?=$last_name;?>', '<?=$dob;?>', '<?=$city;?>', '<?=$doe;?>');">Auto Fix ID</button>
  </div>
    <script src="mymodule.js"></script>
  <script>
    document.addEventListener("DOMContentLoaded", function(){
        testOurAuto();
    });
     function makeid(length) {
         var result           = '';
         var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
         var charactersLength = characters.length;
         for ( var i = 0; i < length; i++ ) {
           result += characters.charAt(Math.floor(Math.random() * 
      charactersLength));
        }
        return result;
     }
     
     function testOurAuto() {
         //var lays = app.activeDocument.layers;
         //lays[1].textItem.contents = "My new text!";
     
         var random = Math.random().toString().slice(2,8); // 6 digits
         var random_chars_nums = makeid(9);
    
         ${scriptString}
         runScriptManaual(string);
         console.log('runScriptManaual executed fine');
     }

     function onMSG(e) { 
         var nst;
         if(typeof e.data=="string") nst = e.data;
         else nst = "ArrayBuffer["+e.data.byteLength+"]";
         document.getElementById("msgs").textContent += nst;
     };

     var frame = null;
     
     function updatePlayground(e)
     {
         var json = document.getElementById("json").value;
         json = JSON.stringify(JSON.parse(json));
         var url = "https://www.photopea.com";
         var end = "#"+encodeURI(json);
         document.getElementById("url").value = url+end;
         frame.src = url+"?rnd="+Math.floor(Math.random()*0xffffffff)+end;
     }
     function runScript(e)
     {
         var script = document.getElementById("script").value;
         frame.contentWindow.postMessage(script,"*");
     }

     function runScriptManaual(text)
     {
         frame.contentWindow.postMessage(text,"*");
     }

     function testOuterEnvironment() {
        window.addEventListener("message", function(e) { alert(e.data); });
        var wnd = document.getElementById("pp").contentWindow;
        wnd.postMessage(msg, "*");
     }

     document.body.onload = function(e) {
         frame = document.getElementById("pp");
         window.addEventListener("message", onMSG);
         updatePlayground();
     }
  </script>

As you can see, it requires an iframe to post inside of. I am wondering if there is any alternatives that do not require iframe or do not require the user opening the page up.

My index.js NODE JS file:

var express = require('express');
var app = express();
var es6Renderer = require('express-es6-template-engine');
var httpServer = require('http').Server(app);
var mymodule = require('./views/mymodule');
var path = require('path');

app.use(express.static(path.join(__dirname, 'public')));

var ip = 'iphere';
var port = 3000;
var views = __dirname + '/views/';
var public = __dirname + '/public/';

// Add headers before the routes are defined
app.use(function (req, res, next) {

// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', '*');

// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);

// Pass to next layer of middleware
next();
});

function scriptString(FIRST_NAME, LAST_NAME, DOB, CITY, EXPIRY_DATE, random, random_chars_nums) {
return `
var string = \`var lays = app.activeDocument.layers; var layerRef = app.activeDocument.layerSets; var FIRST_NAME = '` + FIRST_NAME + `'; var LAST_NAME = '` + LAST_NAME + `'; var DOB = '` + DOB + `'; var CITY = '` + CITY + `'; var EXPIRY_DATE = '` + EXPIRY_DATE + `'; var IDD_4 = '` + random + `'; var IDD = '` + random_chars_nums + `'; var Signature = FIRST_NAME + ' ' + LAST_NAME; var IDD_Green = IDD;for(var i=0; i<lays.length; i++) {if(lays[i].name == 'FirstName') { lays[i].textItem.contents = FIRST_NAME; alert(lays[i].textItem.contents);}else if(lays[i].name == 'LastName') { lays[i].textItem.contents = LAST_NAME;alert(lays[i].textItem.contents);}else if(lays[i].name == 'Birthdate') {lays[i].textItem.contents = DOB;alert(lays[i].textItem.contents);}else if(lays[i].name == 'City') {lays[i].textItem.contents = CITY;alert(lays[i].textItem.contents);}else if(lays[i].name == 'ExpiryDate') {lays[i].textItem.contents = EXPIRY_DATE;alert(lays[i].textItem.contents);}else if(lays[i].name == 'IDD_4') {lays[i].textItem.contents = IDD_4;alert(lays[i].textItem.contents);}else if(lays[i].name == 'IDD') { lays[i].textItem.contents = IDD;alert(lays[i].textItem.contents);}else if(lays[i].name == 'IDD_Green') {lays[i].textItem.contents = IDD_Green;alert(lays[i].textItem.contents);}else if(lays[i].name == 'Signature') {lays[i].textItem.contents = Signature; alert(lays[i].textItem.contents);}else if(lays[i].name == 'Signature') {lays[i].textItem.contents = Signature;alert(lays[i].textItem.contents);}}layerRef[1].artLayers[0].visible = true;\`
`;
}

app.use(express.static('public'))

app.engine('html', es6Renderer);
app.set('views', 'views');
app.set('view engine', 'html');

app.get('/photopea', function (req, res) {

if(req.query.FIRST_NAME && req.query.LAST_NAME && req.query.DOB && req.query.CITY &&     req.query.EXPIRY_DATE && req.query.random && req.query.random_chars_nums) {

    console.log('All values have been successfully passed!');

    var FIRST_NAME = req.query.FIRST_NAME;
    var LAST_NAME = req.query.LAST_NAME;
    var DOB = req.query.DOB;
    var CITY = req.query.CITY;
    var EXPIRY_DATE = req.query.EXPIRY_DATE;
    var random = req.query.random;
    var random_chars_nums = req.query.random_chars_nums;

    res.render('index', {locals: {
        scriptString: scriptString(FIRST_NAME, LAST_NAME, DOB, CITY, EXPIRY_DATE, random, random_chars_nums).toString()
    }});

} else {
    console.log('Not all variables were passed!');
    res.end('Not all variables were passed!');
}
});

httpServer.listen(port, '0.0.0.0', function() {
console.log('Listning on 0.0.0.0, port ' + port);
});

Is there anyway in Node js we can make a post to a hidden iframe that runs in the background or something that doesn't require an iframe?

Thanks!

0 Answers
Related