Okay, nobody has a solution, so I built a solution. This is a PHP script. (Shuddup – I like php!) It emulates the login to the GlowForge cloud web interface and then retrieves the machine information. If it works, you’ll see a bunch of json output.
You only need to set your login email address, login password, and the path for storing the cookie file.
Warning: Since this script requires your username and password for getting into your glowforge account (and this forum), be very careful to not put it on a public-facing web server!
<?php
/**********************************************
Script to check GlowForge status
Created by Neal Krawetz, 2023-12-28
License: Public domain, not responsible for how you use it or any damage it may cause.
Use at your own risk!
**********************************************/
global $CookieJar;
// BEGIN CUSTOMIZATION
$USER='YOUR_EMAIL_ADDRESS'; // this is your GF login
$PASS='YOUR_PASSWORD'; // this is your GF password
$CookieJar='/dev/shm/gf-cookies.txt'; // path to cookie storage
$Verbose=false; // enable for debugging
// END CUSTOMIZATION
function GetURL($method,$url,$parameters=false,$verbose=false)
{
global $CookieJar;
$uas = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0';
$options = array(
CURLOPT_URL => $url, // set the URL
CURLOPT_USERAGENT => $uas, // set the user-agent string
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // DON'T return headers in addition to content
CURLINFO_HEADER_OUT => true, // Show me the posted request
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLOPT_SSL_VERIFYPEER => true, // Validate SSL Certificates
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => strtoupper($method), // request method
CURLOPT_COOKIESESSION => true, // store session cookies
CURLOPT_COOKIEJAR => $CookieJar, // where to store cookies
CURLOPT_COOKIEFILE => $CookieJar, // where to read cookies
);
$out=array();
if ($parameters !== false)
{
$options[CURLOPT_HTTPHEADER] = array('Content-Type: application/x-www-form-urlencoded');
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = http_build_query($parameters);
$out['post_parameters'] = $options[CURLOPT_POSTFIELDS];
}
$ch = curl_init(); // curl handle
curl_setopt_array($ch, $options);
$out['body'] = curl_exec($ch);
$out['err'] = curl_errno($ch);
$out['errmsg'] = curl_error($ch);
$out['header'] = curl_getinfo($ch);
curl_close($ch);
if ($verbose) { print_r($out); }
return($out);
}
/*******************************************
Check if it needs to get cookies
*******************************************/
$NeedCookies=true; // assume it needs cookies
if (is_file($CookieJar))
{
// Check if cookies exist and have not expired
$fp=fopen($CookieJar,"r");
if ($fp)
{
// There are 3 necessary cookies:
// #HttpOnly_.glowforge.com
// #HttpOnly_.accounts.glowforge.com
// .glowforge.com
$Now=time();
$Cookie=array();
while($line=fgets($fp))
{
$line=explode("\t",$line);
if (!isset($line[6])) { continue; } // bad line
if (!is_numeric($line[4])) { continue; } // bad line
if (intval($line[4])+30 <= $Now) { continue; } // needs to be valid for at least 30 seconds
$Cookie[$line[0]]=1; // looks valid, so store it
}
fclose($fp);
// Are all of the essential cookies valid?
if (isset($Cookie['#HttpOnly_.glowforge.com']) &&
isset($Cookie['#HttpOnly_.accounts.glowforge.com']) &&
isset($Cookie['.glowforge.com']))
{
$NeedCookies=false; // already got good cookies!
}
}
}
/*******************************************
Get cookies as needed.
*******************************************/
if ($NeedCookies)
{
// Get initial Google cookies.
if ($Verbose) { echo "Get cookies!\n"; }
if (is_file($CookieJar)) { unlink($CookieJar); } // toss any old cookies
$out=GetURL("GET","https://app.glowforge.com/");
if (!isset($out['header']['http_code']) || (intval($out['header']['http_code'])!==200))
{
echo "Error: Bad return code.\n";
print_r($out);
exit;
}
// Grab the authenticity token!
// E.g.: <input type="hidden" name="authenticity_token" value="BlaBlaBla" />
// This token is supposed to deter bots and scripts, uh, like this script.
$p=strpos($out['body'],'name="authenticity_token"'); // find the field
$Tok=substr($out['body'],$p);
$p=strpos($Tok,'value="'); // find the value
$Tok=substr($Tok,$p+7);
$p=strpos($Tok,'"'); // find the end of the value
$Tok=substr($Tok,0,$p);
#echo "Tok=$Tok\n";
// Login to get session cookies.
if ($Verbose) { echo "Post login\n"; }
$Post=array();
$Post['authenticity_token'] = $Tok;
$Post['user[email]'] = $USER;
$Post['user[password]'] = $PASS;
$Post['user[remember_me]'] = 0;
$Post['commit'] = 'Sign In';
$out=GetURL("POST","https://accounts.glowforge.com/users/sign_in",$Post);
if (!isset($out['header']['http_code']) || (intval($out['header']['http_code'])!==200))
{
echo "Error: Bad login.\n";
print_r($out);
exit;
}
} // if $NeedCookies
/*******************************************
Get machines! (Requires valid login and session cookies.)
*******************************************/
$out=GetURL("GET","https://api.glowforge.com/gfcore/users/machines");
if (!isset($out['header']['http_code']) || (intval($out['header']['http_code'])!==200))
{
echo "Error: Bad get machines.\n";
print_r($out);
exit;
}
echo $out['body']; // output the json
?>
Since it requires PHP, you can run it from the command-line, like:
php ./gf-getmachine.php > machines.json
cat machines.json | json_pp | less
If it needs to get the login cookies, then this may take 2-3 seconds to complete.
If it already has valid login cookies (from a previous run), then it takes less than a second to complete.
I don’t know if there’s a login limit or how often you can call it. I was running it every few minutes while trying to build and debug it, and I didn’t get locked out.
I strongly suggest NOT trying to abuse it by calling it ever few seconds (or more often). Otherwise, GF might notice and disable this capability or start locking accounts for abusive behavior. (I know I would if I were them.)