From fcb3642ac5a5226befe0c3b97ad680f13a629657 Mon Sep 17 00:00:00 2001 From: Sepp Jeremiah Morris Date: Fri, 9 Feb 2024 20:34:55 +0100 Subject: [PATCH] Some testing & cleanup --- .gitignore | 2 - app.go | 2 +- app/application.js | 11 +- app/assets/img/icons/jcat@1080.png | Bin 0 -> 9385 bytes app/assets/img/icons/jcat@720.png | Bin 0 -> 7549 bytes app/assets/img/jctools.png | Bin 0 -> 4993 bytes app/js/jclog.js | 56 --- app/js/jcm.js | 562 +++++++++++++++++++++++++++++ app/js/jsvtestpage.js | 205 +++++++++++ app/js/storagetest.js | 45 +++ app/xml/devtools.xml | 43 +++ app/xml/dvt/jsvtestpage.xml | 8 + app/xml/dvt/storagetest.xml | 29 ++ app/xml/dvt/testpage.xml | 9 + app/xml/home.xml | 33 -- dnsResolver.go | 59 +-- main.go | 2 +- settings.cfg | 2 +- webServer.go | 50 +-- 19 files changed, 957 insertions(+), 161 deletions(-) create mode 100644 app/assets/img/icons/jcat@1080.png create mode 100644 app/assets/img/icons/jcat@720.png create mode 100644 app/assets/img/jctools.png delete mode 100644 app/js/jclog.js create mode 100644 app/js/jcm.js create mode 100644 app/js/jsvtestpage.js create mode 100644 app/js/storagetest.js create mode 100644 app/xml/devtools.xml create mode 100644 app/xml/dvt/jsvtestpage.xml create mode 100644 app/xml/dvt/storagetest.xml create mode 100644 app/xml/dvt/testpage.xml delete mode 100644 app/xml/home.xml diff --git a/.gitignore b/.gitignore index 9cbf32f..a55d58d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,3 @@ /assets/certificates/certificate.cer /assets/certificates/certificate.pem /assets/certificates/private.key -/app/assets/img/icons/jcat@720.png -/app/assets/img/icons/jcat@1080.png diff --git a/app.go b/app.go index 74397a9..6fa4714 100644 --- a/app.go +++ b/app.go @@ -112,7 +112,7 @@ func displayCinfo() { fmt.Println("| |") fmt.Println("| *** WEB *** |") fmt.Println("| |") - fmt.Println("| https_port = ", config.HttpsPort, " |") + fmt.Println("| https_port = ", config.HttpsPort, " |") fmt.Println("| https_port = ", config.HttpPort, " |") fmt.Println("| |") fmt.Println("=========================================") diff --git a/app/application.js b/app/application.js index 58e1077..75278aa 100644 --- a/app/application.js +++ b/app/application.js @@ -10,8 +10,7 @@ atv.onAppEntry = function () { fetchSettings(function() { overrideConsoleLog(); console.log("Successfully overwritten console log, sending logs to JCATHOST now.") - console.log("Received ATVCSETTINGS From JCATHOST."); - console.log("Starting JellyCAT-JS on AppleTV...") + console.log("Received ATVCSETTINGS From JCATHOST. And starting JellyCAT-APP-JS on AppleTV..."); jcatMain(); }); } @@ -22,16 +21,16 @@ atv.onAppExit = function() { // *************************************************** // JellyCAT Main | Main JS app function -// Help +// Help I'm even worse at JS function jcatMain(){ - atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/home.xml"); + atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/devtools.xml"); } // *************************************************** // JellyCAT Logger | Jclogger // Function to override console.log, console.error, and console.warn and send logs to the JellyCAT stHack server -// We shall never send any sensitive information!! + function overrideConsoleLog() { var originalConsoleLog = console.log; var originalConsoleError = console.error; @@ -81,7 +80,7 @@ function logToServer(logData) { // *************************************************** // JellyCAT Host fetcher // Function to fetch information we need from the host server -// Function to fetch JSON from the HTTP URL using XMLHttpRequest +// fetch JSON from the HTTP URL using XMLHttpRequest function fetchSettings(callback) { var xhr = new XMLHttpRequest(); diff --git a/app/assets/img/icons/jcat@1080.png b/app/assets/img/icons/jcat@1080.png new file mode 100644 index 0000000000000000000000000000000000000000..a3a787500faf543fd30ff8c4517d6ed9e7b13b5b GIT binary patch literal 9385 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 literal 0 HcmV?d00001 diff --git a/app/assets/img/icons/jcat@720.png b/app/assets/img/icons/jcat@720.png new file mode 100644 index 0000000000000000000000000000000000000000..6e9b24b9ab623779fa2128553cefcacdeb34c5a8 GIT binary patch literal 7549 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 literal 0 HcmV?d00001 diff --git a/app/assets/img/jctools.png b/app/assets/img/jctools.png new file mode 100644 index 0000000000000000000000000000000000000000..0b4842cc62bcd2398f8490f08b185a9e50b09044 GIT binary patch literal 4993 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 OGIOl8NvV \ + \ + \ + \ + '; + + return atv.parseXML(errorXML); + }, + + siteUnavailableError: function() { + // TODO: localize + return this.makeErrorDocument("JellyCAT is currently unavailable. Try again later.", "Check JCHOST for log information."); + }, + + loadError: function(message, description) { + atv.loadXML(this.makeErrorDocument(message, description)); + }, + + loadAndSwapError: function(message, description) { + atv.loadAndSwapXML(this.makeErrorDocument(message, description)); + }, + + loadURLInternal: function(url, method, headers, body, loader) { + var me = this, + xhr, + proxy = new atv.ProxyDocument; + + proxy.show(); + + proxy.onCancel = function() { + if ( xhr ) { + xhr.abort(); + } + }; + + xhr = me.makeRequest(url, method, headers, body, function(xml) { + try { + loader(proxy, xml); + } catch(e) { + console.error("Caught exception in for " + url + ". " + e); + loader(me.siteUnavailableError()); + } + }); + }, + + loadURL: function( options ) { //url, method, headers, body, processXML) { + var me = this; + if( typeof( options ) === "string" ) { + var url = options; + } else { + var url = options.url, + method = options.method || null, + headers = options.headers || null, + body = options.body || null, + processXML = options.processXML || null; + } + + this.loadURLInternal(url, method, headers, body, function(proxy, xml) { + if(typeof(processXML) == "function") processXML.call(this, xml); + try { + proxy.loadXML(xml, function(success) { + if ( !success ) { + console.log("loadURL failed to load " + url); + proxy.loadXML(me.siteUnavailableError()); + } + }); + } catch (e) { + console.log("loadURL caught exception while loading " + url + ". " + e); + proxy.loadXML(me.siteUnavailableError()); + } + }); + }, + + // loadAndSwapURL can only be called from page-level JavaScript of the page that wants to be swapped out. + loadAndSwapURL: function( options ) { //url, method, headers, body, processXML) { + var me = this; + if( typeof( options ) === "string" ) { + var url = options; + } else { + var url = options.url, + method = options.method || null, + headers = options.headers || null, + body = options.body || null, + processXML = options.processXML || null; + } + + this.loadURLInternal(url, method, headers, body, function(proxy, xml) { + if(typeof(processXML) == "function") processXML.call(this, xml); + try { + proxy.loadXML(xml, function(success) { + if ( success ) { + atv.unloadPage(); + } else { + console.log("loadAndSwapURL failed to load " + url); + proxy.loadXML(me.siteUnavailableError(), function(success) { + if ( success ) { + atv.unloadPage(); + } + }); + } + }); + } catch (e) { + console.error("loadAndSwapURL caught exception while loading " + url + ". " + e); + proxy.loadXML(me.siteUnavailableError(), function(success) { + if ( success ) { + atv.unloadPage(); + } + }); + } + }); + }, + + /** + * Used to manage setting and retrieving data from local storage + */ + data: function(key, value) { + if(key && value) { + try { + atv.localStorage.setItem(key, value); + return value; + } catch(error) { + console.error('Failed to store data element: '+ error); + } + + } else if(key) { + try { + return atv.localStorage.getItem(key); + } catch(error) { + console.error('Failed to retrieve data element: '+ error); + } + } + return null; + }, + + deleteData: function(key) { + try { + atv.localStorage.removeItem(key); + } catch(error) { + console.error('Failed to remove data element: '+ error); + } + }, + + + /** + * @params options.name - string node name + * @params options.text - string textContent + * @params options.attrs - array of attribute to set {"name": string, "value": string, bool} + * @params options.children = array of childNodes same values as options + * @params doc - document to attach the node to + * returns node + */ + createNode: function(options, doc) { + var doc = doc || document; + options = options || {}; + + if(options.name && options.name != '') { + var newElement = doc.makeElementNamed(options.name); + + if(options.text) newElement.textContent = options.text; + + if(options.attrs) { + options.attrs.forEach(function(e, i, a) { + newElement.setAttribute(e.name, e.value); + }, this); + } + + if(options.children) { + options.children.forEach(function(e,i,a) { + newElement.appendChild( this.createNode( e, doc ) ); + }, this) + } + + return newElement; + } + }, + + validEmailAddress: function( email ) { + var emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, + isValid = email.search( emailRegex ); + return ( isValid > -1 ); + }, + + softwareVersionIsAtLeast: function( version ) { + var deviceVersion = atv.device.softwareVersion.split('.'), + requestedVersion = version.split('.'); + + // We need to pad the device version length with "0" to account for 5.0 vs 5.0.1 + if( deviceVersion.length < requestedVersion.length ) { + var difference = requestedVersion.length - deviceVersion.length, + dvl = deviceVersion.length; + + for( var i = 0; i < difference; i++ ) { + deviceVersion[dvl + i] = "0"; + }; + }; + + // compare the same index from each array. + for( var c = 0; c < deviceVersion.length; c++ ) { + var dv = deviceVersion[c], + rv = requestedVersion[c] || "0"; + + if( parseInt( dv ) > parseInt( rv ) ) { + return true; + } else if( parseInt( dv ) < parseInt( rv ) ) { + return false; + }; + }; + + // If we make it this far the two arrays are identical, so we're true + return true; + }, + + shuffleArray: function( arr ) { + var tmp, current, top = arr.length; + + if(top) { + while(--top) { + current = Math.floor(Math.random() * (top + 1)); + tmp = arr[current]; + arr[current] = arr[top]; + arr[top] = tmp; + }; + }; + + return arr; + }, + + loadTextEntry: function( textEntryOptions ) { + var textView = new atv.TextEntry; + + textView.type = textEntryOptions.type || "emailAddress"; + textView.title = textEntryOptions.title || ""; + textView.image = textEntryOptions.image || null; + textView.instructions = textEntryOptions.instructions || ""; + textView.label = textEntryOptions.label || ""; + textView.footnote = textEntryOptions.footnote || ""; + textView.defaultValue = textEntryOptions.defaultValue || null; + textView.defaultToAppleID = textEntryOptions.defaultToAppleID || false; + textView.onSubmit = textEntryOptions.onSubmit, + textView.onCancel = textEntryOptions.onCancel, + + textView.show(); + }, + + log: function ( message , level ) { + var debugLevel = atv.sessionStorage.getItem( "DEBUG_LEVEL" ), + level = level || 0; + + if( level <= debugLevel ) { + console.log( message ); + } + }, + + accessibilitySafeString: function ( string ) { + var string = unescape( string ); + + string = string + .replace( /&/g, 'and' ) + .replace( /&/g, 'and' ) + .replace( /</g, 'less than' ) + .replace( /\/g, 'greater than' ); + + return string; + } +}; + +// Extend atv.ProxyDocument to load errors from a message and description. +if( atv.ProxyDocument ) { + atv.ProxyDocument.prototype.loadError = function(message, description) { + var doc = atvutils.makeErrorDocument(message, description); + this.loadXML(doc); + } +} + + +// atv.Document extensions +if( atv.Document ) { + atv.Document.prototype.getElementById = function(id) { + var elements = this.evaluateXPath("//*[@id='" + id + "']", this); + if ( elements && elements.length > 0 ) { + return elements[0]; + } + return undefined; + } +} + + +// atv.Element extensions +if( atv.Element ) { + atv.Element.prototype.getElementsByTagName = function(tagName) { + return this.ownerDocument.evaluateXPath("descendant::" + tagName, this); + } + + atv.Element.prototype.getElementByTagName = function(tagName) { + var elements = this.getElementsByTagName(tagName); + if ( elements && elements.length > 0 ) { + return elements[0]; + } + return undefined; + } +} + +// Simple Array Sorting methods +Array.prototype.sortAsc = function() { + this.sort(function( a, b ){ + return a - b; + }); +}; + +Array.prototype.sortDesc = function() { + this.sort(function( a, b ){ + return b - a; + }); +}; + + +// Date methods and properties +Date.lproj = { + "DAYS": { + "en": { + "full": ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + "abbrv": ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] + }, + "en_GB": { + "full": ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + "abbrv": ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] + } + }, + "MONTHS": { + "en": { + "full": ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + "abbrv": ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + }, + "en_GB": { + "full": ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + "abbrv": ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + } + } +} + +Date.prototype.getLocaleMonthName = function( type ) { + var language = atv.device.language, + type = ( type === true ) ? "abbrv" : "full", + MONTHS = Date.lproj.MONTHS[ language ] || Date.lproj.MONTHS[ "en" ]; + + return MONTHS[ type ][ this.getMonth() ]; +}; + +Date.prototype.getLocaleDayName = function( type ) { + var language = atv.device.language, + type = ( type === true ) ? "abbrv" : "full", + DAYS = Date.lproj.DAYS[ language ] || Date.lproj.DAYS[ "en" ]; + + return DAYS[ type ][ this.getDay() ]; +}; + +Date.prototype.nextDay = function( days ) { + var oneDay = 86400000, + days = days || 1; + this.setTime( new Date( this.valueOf() + ( oneDay * days ) ) ); +}; + +Date.prototype.prevDay = function( days ) { + var oneDay = 86400000, + days = days || 1; + this.setTime( new Date( this.valueOf() - ( oneDay * days ) ) ); +}; + + +// String Trim methods +String.prototype.trim = function ( ch ) +{ + var ch = ch || '\\s', + s = new RegExp( '^['+ch+']+|['+ch+']+$','g'); + return this.replace(s,''); +}; + +String.prototype.trimLeft = function ( ch ) +{ + var ch = ch || '\\s', + s = new RegExp( '^['+ch+']+','g'); + return this.replace(s,''); +}; + +String.prototype.trimRight = function ( ch ) +{ + var ch = ch || '\\s', + s = new RegExp( '['+ch+']+$','g'); + return this.replace(s,''); +}; + +String.prototype.xmlEncode = function() +{ + var string = unescape( this ); + + string = string + .replace( /&/g, '&' ) + .replace( /\/g, '>' ); + + return string; +}; + +console.log('Reached EOF!'); + diff --git a/app/js/jsvtestpage.js b/app/js/jsvtestpage.js new file mode 100644 index 0000000..827752b --- /dev/null +++ b/app/js/jsvtestpage.js @@ -0,0 +1,205 @@ +/* +* https://github.com/wahlmanj/sample-aTV/blob/dba73806c21183fb35d6edca94b960691d8e5d66/js/views/text-view/text-view.js +* text-view.js - Demonstrates atv.TextView +* TextView's have an attributedString parameter that is an Object with two required properties: string and attributes. +* - string is the string displayed in the text view on screen. +* - attributes is an Object with two required properties (pointSize and color) and optional properties (alignment, weight, and breakMode). +* +* attribute Object properties +* pointSize: Required. A number that is the size of the font in points +* color: Required. An object with 3 required properties (red, green, and blue) and one optional property (alpha). Each of the color components is a number from 0 to 1. +* alignment: Optional. left, right, center, or justify +* weight: Optional. light, normal, or heavy +* breakMode: Optional. clip, word-wrap, truncate-head, truncate-tail, or truncate-middle. + clip: the text will be displayed on a single line and cut off at the end of the text view + word-wrap: the text will word wrap until there is no more space, at which point it is clipped to the text view + truncate-head: the text will be displayed on a single line with an ellipsis at the beginning if the string would be clipped otherwise + truncate-tail: the text will be displayed on a single line with an ellipsis at the end if the string would be clipped otherwise + truncate-middle: the text will be displayed on a single line with an ellipsis in the middle if the string would be clipped otherwise +*/ + +var loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ut arcu ut lectus pellentesque ultrices. Sed eu neque et nisl feugiat interdum. Praesent rutrum magna in massa consectetur semper. Nullam gravida odio sit amet purus mattis porta. Sed in est suscipit ipsum imperdiet dapibus. Curabitur cursus fermentum lectus, quis aliquam magna convallis vitae. Maecenas egestas molestie rhoncus. Morbi erat neque, egestas quis condimentum quis, mattis a est. Maecenas vel ipsum a dui posuere tincidunt. Suspendisse tincidunt posuere pretium. Sed in quam eget nibh ultricies dictum. Aliquam est lorem, vestibulum nec congue id, tincidunt vel nunc. Nulla in sem massa, a fermentum purus. In hac habitasse platea dictumst. Vestibulum euismod iaculis justo id rhoncus."; + +var screenFrame = atv.device.screenFrame; +var containerView = new atv.View(); +var exampleTextViews = []; +containerView.frame = screenFrame; + +var startY = screenFrame.height * 0.05; +var currentY = startY; +var hPadding = screenFrame.width * 0.03; +var currentX = hPadding; +var height = screenFrame.height * 0.12; +var width = screenFrame.width * 0.25; + +function addTextView () { + var textView = new atv.TextView(); + textView.backgroundColor = { red: 0.2, blue: 0.2, green: 0.2 }; + + var vSpacing = screenFrame.height * 0.01; + + textView.frame = { + x: currentX, + y: currentY, + width: width, + height: height + }; + + currentY += height + vSpacing; + + if ( currentY + height + vSpacing > containerView.frame.height ) + { + currentY = startY; + currentX += width + hPadding; + } + + exampleTextViews.push(textView); + + return textView; +} + +// +// TextView using only the required attributes +// +var onlyRequiredAttributesView = addTextView(); +onlyRequiredAttributesView.attributedString = { + string: "Only Required Attributes: " + loremIpsum, + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 } + } +}; + +// +// TextView's demonstrating alignments +// +var rightAlignmentView = addTextView(); +rightAlignmentView.attributedString = { + string: "Right Alignment", + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + alignment: "right" + } +}; + +var centerAlignmentView = addTextView(); +centerAlignmentView.attributedString = { + string: "Center Alignment", + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + alignment: "center" + } +}; + +var leftAlignmentView = addTextView(); +leftAlignmentView.attributedString = { + string: "Left Alignment", + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + alignment: "left" + } +}; + +// +// TextView's demonstrating weights +// +var normalWeight = addTextView(); +normalWeight.attributedString = { + string: "Normal Weight", + attributes: { + // Required attributes + pointSize: 40.0, + color: { red: 1, blue: 1, green: 1 }, + weight: "normal" + } +}; + +var heavyWeight = addTextView(); +heavyWeight.attributedString = { + string: "Heavy Weight", + attributes: { + // Required attributes + pointSize: 40.0, + color: { red: 1, blue: 1, green: 1 }, + weight: "heavy" + } +}; + +var lightWeight = addTextView(); +lightWeight.attributedString = { + string: "Light Weight", + attributes: { + // Required attributes + pointSize: 40.0, + color: { red: 1, blue: 1, green: 1 }, + weight: "light" + } +}; + +// +// TextView's demonstrating breakModes +// +var clip = addTextView(); +clip.attributedString = { + string: "clip: " + loremIpsum, + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + breakMode: "clip" + } +}; + +var wordWrap = addTextView(); +wordWrap.attributedString = { + string: "word-wrap: " + loremIpsum, + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + breakMode: "word-wrap" + } +}; + +var truncateHead = addTextView(); +truncateHead.attributedString = { + string: loremIpsum + " truncate-head", + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + breakMode: "truncate-head" + } +}; + +var truncateTail = addTextView(); +truncateTail.attributedString = { + string: "truncate-tail: " + loremIpsum, + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + breakMode: "truncate-tail" + } +}; + +var truncateMiddle = addTextView(); +truncateMiddle.attributedString = { + string: "truncate-middle: " + loremIpsum, + attributes: { + // Required attributes + pointSize: 20.0, + color: { red: 1, blue: 1, green: 1 }, + breakMode: "truncate-middle" + } +}; + +containerView.subviews = exampleTextViews; +controller.view = containerView; \ No newline at end of file diff --git a/app/js/storagetest.js b/app/js/storagetest.js new file mode 100644 index 0000000..f948743 --- /dev/null +++ b/app/js/storagetest.js @@ -0,0 +1,45 @@ +// /\_/| +// { ' ' } JellyCAT +// \____\ + +function printSessionStorage() { + + var keys = ['test', 'exampleKey2', 'exampleKey3']; + + keys.forEach(function(key) { + var value = atv.sessionStorage.getItem(key); + if (value !== null) { + console.log(key + ": " + value); + } else { + console.log("No value found for key: " + key); + } + }); +} + +function printLocalStorage() { + + var keys = ['test', 'exampleKey2', 'exampleKey3']; + + keys.forEach(function(key) { + var value = atv.localStorage.getItem(key); + if (value !== null) { + console.log(key + ": " + value); + } else { + console.log("No value found for key: " + key); + } + }); +} + +function setTestSessionStorageItem() { + // Set an example item in sessionStorage + atv.sessionStorage.setItem('test', 'exampleValueForSessionStorage'); + console.log('Test item set in sessionStorage.'); +} + +function setTestLocalStorageItem() { + // Set an example item in sessionStorage + atv.localStorage.setItem('test', 'exampleValueForLocalStorage'); + console.log('Test item set in localStorage.'); +} + + diff --git a/app/xml/devtools.xml b/app/xml/devtools.xml new file mode 100644 index 0000000..f3d1e6b --- /dev/null +++ b/app/xml/devtools.xml @@ -0,0 +1,43 @@ + + + +