diff --git a/DesktopReact/DesktopApp.js b/DesktopReact/DesktopApp.js
new file mode 100644
index 000000000..4ac8410b5
--- /dev/null
+++ b/DesktopReact/DesktopApp.js
@@ -0,0 +1,81 @@
+const express = require("./backend/src/index");
+exports.newDesktopApp = function newDesktopApp() {
+
+ let thisObject = {
+ userProfiles: undefined,
+ p2pNetworkClient: undefined,
+ p2pNetwork: undefined,
+ p2pNetworkPeers: undefined,
+ webSocketsInterface: undefined,
+ webAppInterface: undefined,
+ p2pNetworkInterface: undefined,
+ socialGraph: undefined,
+ run: run
+ }
+
+ DK.desktopApp = thisObject
+
+ return thisObject
+
+ async function run() {
+
+ await setupNetwork()
+ await setupServices()
+
+ async function setupNetwork() {
+ /*
+ We set up ourselves as a Network Client.
+ */
+ thisObject.p2pNetworkClient = SA.projects.network.modules.p2pNetworkClient.newNetworkModulesP2PNetworkClient()
+ await thisObject.p2pNetworkClient.initialize()
+ /*
+ We will read all user profiles plugins and get from there our network identity.
+ */
+ thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles()
+ await thisObject.userProfiles.initialize(global.env.DESKTOP_APP_SIGNING_ACCOUNT, thisObject.p2pNetworkClient)
+ /*
+ We set up the P2P Network.
+ */
+ thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork()
+ await thisObject.p2pNetwork.initialize('Network Client')
+ /*
+ Set up the connections to network nodes.
+ */
+ thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers()
+ await thisObject.p2pNetworkPeers.initialize(
+ 'Network Client',
+ thisObject.p2pNetworkClient,
+ thisObject.p2pNetwork,
+ global.env.DESKTOP_APP_MAX_OUTGOING_PEERS
+ )
+ }
+
+ async function setupServices() {
+ /*
+ This is where we will process all the messages comming from our web app.
+ */
+ thisObject.webAppInterface = DK.projects.socialTrading.modules.webAppInterface.newSocialTradingModulesWebAppInterface() // this sends events to the p2p network
+ /*
+ This is where we will process all the events comming from the p2p network.
+ */
+ thisObject.p2pNetworkInterface = DK.projects.socialTrading.modules.p2pNetworkInterface.newSocialTradingModulesP2PNetworkInterface() // this receives events from p2p network
+ /*
+ This is the Personal Social Graph for the user running this App.
+ */
+ thisObject.socialGraph = DK.projects.socialTrading.modules.socialGraph.newSocialTradingModulesSocialGraph() //
+ await thisObject.socialGraph.initialize()
+
+
+ let express = require('./backend/src/index')
+ let expressPort = JSON.parse(DK.desktopApp.p2pNetworkClient.node.config).webPort;
+ express.startExpress(expressPort,SA);
+ console.log('express Interface ................................................ Listening at port ' + expressPort);
+
+ /*TODO change this to have a definite port number*/
+ let react = require('./frontend/scripts/start')
+ let reactPort = (+JSON.parse(DK.desktopApp.p2pNetworkClient.node.config).webPort + 1);
+ react.start(reactPort);
+ console.log('react Interface ................................................ Listening at port ' + reactPort);
+ }
+ }
+}
diff --git a/DesktopReact/UI/WebApp.js b/DesktopReact/UI/WebApp.js
new file mode 100644
index 000000000..16d781e44
--- /dev/null
+++ b/DesktopReact/UI/WebApp.js
@@ -0,0 +1,367 @@
+function newWebApp() {
+ /*
+ In it's current state of development, the Web App only has one module.
+
+ Everything is being coded here until some structure emerges.
+ */
+ let thisObject = {
+ messageReceived: messageReceived,
+ initialize: initialize,
+ finalize: finalize
+ }
+
+ return thisObject
+
+ function finalize() {
+
+ }
+
+ async function initialize() {
+ try {
+ setupRootObject(UI, 'UI')
+ setupRootObject(SA, 'SA')
+ await UI.projects.socialTrading.modules.webSocketsWebAppClient.initialize()
+ loadWUserProfileTimeline()
+ loadWhoToFollow()
+ setupEventHandlers()
+ } catch (err) {
+ console.log('[ERROR] initialize -> err.stack = ' + err.stack)
+ }
+ }
+
+ /*
+ function setupRootObject(rootObject, rootObjectName) {
+ /!*
+ Here we will setup the UI object, with all the
+ projects and spaces.
+ *!/
+ for (let i = 0; i < UI.schemas.projectSchema.length; i++) {
+ let projectDefinition = UI.schemas.projectSchema[i]
+ rootObject.projects[projectDefinition.propertyName] = {}
+ let projectInstance = rootObject.projects[projectDefinition.propertyName]
+
+ projectInstance.utilities = {}
+ projectInstance.globals = {}
+ projectInstance.functionLibraries = {}
+ projectInstance.modules = {}
+
+ if (projectDefinition[rootObjectName] === undefined) {
+ continue
+ }
+
+ /!* Set up Globals of this Project *!/
+ if (projectDefinition[rootObjectName].globals !== undefined) {
+ for (let j = 0; j < projectDefinition[rootObjectName].globals.length; j++) {
+ let globalDefinition = projectDefinition[rootObjectName].globals[j]
+
+ if (exports[globalDefinition.functionName] === undefined) {
+ projectInstance.globals[globalDefinition.propertyName] = eval(globalDefinition.functionName + '()')
+ } else {
+ projectInstance.globals[globalDefinition.propertyName] = eval('exports.' + globalDefinition.functionName + '()')
+ }
+ }
+ }
+
+ /!* Set up Utilities of this Project *!/
+ if (projectDefinition[rootObjectName].utilities !== undefined) {
+ for (let j = 0; j < projectDefinition[rootObjectName].utilities.length; j++) {
+ let utilityDefinition = projectDefinition[rootObjectName].utilities[j]
+
+ if (exports[utilityDefinition.functionName] === undefined) {
+ projectInstance.utilities[utilityDefinition.propertyName] = eval(utilityDefinition.functionName + '()')
+ } else {
+ projectInstance.utilities[utilityDefinition.propertyName] = eval('exports.' + utilityDefinition.functionName + '()')
+ }
+ }
+ }
+
+ /!* Set up Function Libraries of this Project *!/
+ if (projectDefinition[rootObjectName].functionLibraries !== undefined) {
+ for (let j = 0; j < projectDefinition[rootObjectName].functionLibraries.length; j++) {
+ let functionLibraryDefinition = projectDefinition[rootObjectName].functionLibraries[j]
+
+ if (exports[functionLibraryDefinition.functionName] === undefined) {
+ projectInstance.functionLibraries[functionLibraryDefinition.propertyName] = eval(functionLibraryDefinition.functionName + '()')
+ } else {
+ projectInstance.functionLibraries[functionLibraryDefinition.propertyName] = eval('exports.' + functionLibraryDefinition.functionName + '()')
+ }
+ }
+ }
+
+ /!* Set up Modules of this Project *!/
+ if (projectDefinition[rootObjectName].modules !== undefined) {
+ for (let j = 0; j < projectDefinition[rootObjectName].modules.length; j++) {
+ let functionLibraryDefinition = projectDefinition[rootObjectName].modules[j]
+
+ if (exports[functionLibraryDefinition.functionName] === undefined) {
+ projectInstance.modules[functionLibraryDefinition.propertyName] = eval(functionLibraryDefinition.functionName + '()')
+ } else {
+ projectInstance.modules[functionLibraryDefinition.propertyName] = eval('exports.' + functionLibraryDefinition.functionName + '()')
+ }
+ }
+ }
+ }
+ }
+ */
+
+ /*
+ async function loadWUserProfileTimeline() {
+ let queryMessage = {
+ queryType: SA.projects.socialTrading.globals.queryTypes.EVENTS,
+ emitterUserProfileId: undefined,
+ initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_LAST,
+ amountRequested: 100,
+ direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_PAST
+ }
+
+ let query = {
+ requestType: 'Query',
+ queryMessage: JSON.stringify(queryMessage)
+ }
+
+ await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
+ JSON.stringify(query)
+ )
+ .then(console.log)
+ .catch(onError)
+
+ function onError(errorMessage) {
+ console.log('[ERROR] Query not executed. ' + errorMessage)
+ console.log('[ERROR] query = ' + JSON.stringify(query))
+ }
+
+ function addToContentDiv(events) {
+ try {
+ let contentDiv = document.getElementById('content-div')
+ /!*
+ Delete al current content.
+ *!/
+ while (contentDiv.childNodes.length > 4) {
+ let childToRemove = contentDiv.childNodes[contentDiv.childNodes.length - 1]
+ contentDiv.removeChild(childToRemove)
+ }
+ /!*
+ Render the timeline.
+ *!/
+ for (let i = 0; i < events.length; i++) {
+ let event = events[i]
+
+ let postDiv = document.createElement("div")
+ postDiv.setAttribute("class", "post-div")
+ let textNode
+
+ switch (event.eventType) {
+ case SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST: {
+ textNode = document.createTextNode(event.emitterUserProfile.userProfileHandle + " POSTED " + event.postText)
+ break
+ }
+ case SA.projects.socialTrading.globals.eventTypes.FOLLOW_USER_PROFILE: {
+ textNode = document.createTextNode(event.emitterUserProfile.userProfileHandle + " FOLLOWED " + event.targetUserProfile.userProfileHandle)
+ break
+ }
+ case SA.projects.socialTrading.globals.eventTypes.UNFOLLOW_USER_PROFILE: {
+ textNode = document.createTextNode(event.emitterUserProfile.userProfileHandle + " UNFOLLOWED " + event.targetUserProfile.userProfileHandle)
+ break
+ }
+ }
+
+ postDiv.appendChild(textNode)
+ contentDiv.appendChild(postDiv)
+ }
+ }
+ catch (err) {
+ console.log('[ERROR] err.stack = ' + err.stack)
+ }
+ }
+ }
+ */
+
+ /*
+ async function loadWhoToFollow() {
+ let queryMessage = {
+ queryType: SA.projects.socialTrading.globals.queryTypes.UNFOLLOWED_USER_PROFILES,
+ emitterUserProfileId: undefined,
+ initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_FIRST,
+ amountRequested: 3,
+ direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_UP
+ }
+
+ let query = {
+ requestType: 'Query',
+ queryMessage: JSON.stringify(queryMessage)
+ }
+
+ await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
+ JSON.stringify(query)
+ )
+ .then(addWhoToFollowTable)
+ .catch(onError)
+
+ function onError(errorMessage) {
+ console.log('[ERROR] Query not executed. ' + errorMessage)
+ console.log('[ERROR] query = ' + JSON.stringify(query))
+ }
+ }
+ */
+
+ function setupEventHandlers() {
+ /*
+ Add events to process button clicks , and mouseWheel.
+ */
+ document.addEventListener("click", onClick)
+ document.addEventListener('mousewheel', onMouseWheel, false)
+
+ async function onClick(event) {
+
+ if (event.target && event.target.nodeName === "BUTTON") {
+ switch (event.target.name) {
+ case 'New Post': {
+ let textArea = document.getElementById("new-post-text-area")
+ await sendNewPostEvent(
+ textArea.value
+ )
+ .then(updateTextArea)
+ .catch(onError)
+
+ function updateTextArea() {
+ textArea.value = ""
+ }
+
+ break
+ }
+ case 'Follow Profile': {
+ await sendTargetUserProfileEvent(
+ event.target.userProfileId,
+ SA.projects.socialTrading.globals.eventTypes.FOLLOW_USER_PROFILE
+ )
+ .then(updateButton)
+ .catch(onError)
+
+ function updateButton() {
+ let span = document.getElementById('profile-to-follow-span-' + event.target.userProfileId)
+ let button = document.getElementById('profile-to-follow-button-' + event.target.userProfileId)
+ span.setAttribute("class", "profile-to-unfollow-span")
+ button.setAttribute("class", "profile-to-unfollow-button")
+ button.name = 'Unfollow Profile'
+ }
+
+ break
+ }
+ case 'Unfollow Profile': {
+ await sendTargetUserProfileEvent(
+ event.target.userProfileId,
+ SA.projects.socialTrading.globals.eventTypes.UNFOLLOW_USER_PROFILE
+ )
+ .then(updateButton)
+ .catch(onError)
+
+/*
+ function updateButton() {
+ let span = document.getElementById('profile-to-follow-span-' + event.target.userProfileId)
+ let button = document.getElementById('profile-to-follow-button-' + event.target.userProfileId)
+ span.setAttribute("class", "profile-to-follow-span")
+ button.setAttribute("class", "profile-to-follow-button")
+ button.name = 'Follow Profile'
+ }
+*/
+
+ break
+ }
+ }
+ }
+
+ /*
+ Error Handling
+ */
+ function onError(errorMessage) {
+ console.log('[ERROR] Click event failed. ' + errorMessage)
+ }
+ }
+
+ function onMouseWheel(event) {
+ let scrollDiv = document.getElementById("scroll-div")
+ scrollDiv.scrollTop = scrollDiv.scrollTop + event.deltaY
+ }
+ }
+
+ async function sendTargetUserProfileEvent(
+ userProfileId,
+ eventType
+ ) {
+
+ return new Promise((resolve, reject) => {
+ asyncCall(resolve, reject)
+ })
+
+ async function asyncCall(resolve, reject) {
+ let eventMessage
+ let event
+
+ eventMessage = {
+ eventType: eventType,
+ eventId: SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId(),
+ targetUserProfileId: userProfileId,
+ timestamp: (new Date()).valueOf()
+ }
+
+ event = {
+ requestType: 'Event',
+ eventMessage: JSON.stringify(eventMessage)
+ }
+
+ await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
+ JSON.stringify(event)
+ )
+ .then(resolve)
+ .catch(onError)
+
+ function onError(errorMessage) {
+ console.log('[ERROR] Event not executed. ' + errorMessage)
+ console.log('[ERROR] event = ' + JSON.stringify(event))
+ reject(errorMessage)
+ }
+ }
+ }
+
+ async function sendNewPostEvent(
+ postText
+ ) {
+
+ return new Promise((resolve, reject) => {
+ asyncCall(resolve, reject)
+ })
+
+ async function asyncCall(resolve, reject) {
+ let eventMessage
+ let event
+
+ eventMessage = {
+ eventType: SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST,
+ eventId: SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId(),
+ postText: postText,
+ timestamp: (new Date()).valueOf()
+ }
+
+ event = {
+ requestType: 'Event',
+ eventMessage: JSON.stringify(eventMessage)
+ }
+
+ await UI.projects.socialTrading.modules.webSocketsWebAppClient.sendMessage(
+ JSON.stringify(event)
+ )
+ .then(resolve)
+ .catch(onError)
+
+ function onError(errorMessage) {
+ console.log('[ERROR] Event not executed. ' + errorMessage)
+ console.log('[ERROR] event = ' + JSON.stringify(event))
+ reject(errorMessage)
+ }
+ }
+ }
+
+ function messageReceived(message) {
+ window.alert(message)
+ }
+}
diff --git a/DesktopReact/backend/src/index.js b/DesktopReact/backend/src/index.js
new file mode 100644
index 000000000..531823d08
--- /dev/null
+++ b/DesktopReact/backend/src/index.js
@@ -0,0 +1,116 @@
+exports.startExpress = (port, SA) => {
+ const express = require("express");
+ const app = express();
+ const webAppInterface = DK.projects.socialTrading.modules.webAppInterface.newSocialTradingModulesWebAppInterface();
+
+ app.use(express.json());
+
+ // define a route handler for the default home page
+ app.get("/health-check", (req, res) => {
+ res.send("all good");
+ });
+
+ app.get("/profiles", async (req, res) => {
+ let profiles = await whoToFollow();
+ console.log(profiles)
+ res.send(profiles);
+ });
+
+ app.post("/follow", async (req, res) => {
+ let follow = followProfile(req.body.userProfileId, SA.projects.socialTrading.globals.eventTypes.FOLLOW_USER_PROFILE);
+ res.send("Followed")
+ });
+
+ app.post("/unFollow", async (req, res) => {
+ let follow = followProfile(req.body.userProfileId, SA.projects.socialTrading.globals.eventTypes.UNFOLLOW_USER_PROFILE);
+ res.send("UnFollow")
+ });
+
+
+ app.post("/post", async (req, res) => {
+ console.log(req)
+ let post = createPost(req);
+ res.send(post)
+ });
+
+ // start the Express server
+ app.listen(port, () => {
+ console.log(`server started at http://localhost:${port}`);
+ });
+
+ async function createPost(postText) {
+ try {
+ let eventMessage;
+ let event;
+
+ eventMessage = {
+ eventType: SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST,
+ eventId: SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId(),
+ postText: postText,
+ timestamp: (new Date()).valueOf()
+ }
+
+ event = {
+ requestType: 'Event',
+ eventMessage: JSON.stringify(eventMessage)
+ }
+
+ return await webAppInterface.sendMessage(
+ JSON.stringify(event)
+ );
+ } catch (e) {
+ console.log(e);
+ return {};
+ }
+ }
+
+ async function whoToFollow() {
+
+ try {
+ let queryMessage = {
+ queryType: SA.projects.socialTrading.globals.queryTypes.UNFOLLOWED_USER_PROFILES,
+ emitterUserProfileId: undefined,
+ initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_FIRST,
+ amountRequested: 3,
+ direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_UP
+ }
+
+ let query = {
+ requestType: 'Query',
+ queryMessage: JSON.stringify(queryMessage)
+ }
+
+ return await webAppInterface.messageReceived(
+ JSON.stringify(query)
+ );
+ } catch (e) {
+ console.log(e);
+ return [];
+ }
+ }
+
+ async function followProfile(userProfileId, eventType) {
+
+ try {
+ let queryMessage = {
+ queryType: SA.projects.socialTrading.globals.queryTypes.UNFOLLOWED_USER_PROFILES,
+ emitterUserProfileId: undefined,
+ initialIndex: SA.projects.socialTrading.globals.queryConstants.INITIAL_INDEX_FIRST,
+ amountRequested: 3,
+ direction: SA.projects.socialTrading.globals.queryConstants.DIRECTION_UP
+ }
+
+ let query = {
+ requestType: 'Query',
+ queryMessage: JSON.stringify(queryMessage)
+ }
+
+ return await webAppInterface.messageReceived(
+ JSON.stringify(query)
+ );
+ } catch (e) {
+ console.log(e);
+ return {};
+ }
+ }
+}
\ No newline at end of file
diff --git a/DesktopReact/frontend/config/env.js b/DesktopReact/frontend/config/env.js
new file mode 100644
index 000000000..cecdd1e46
--- /dev/null
+++ b/DesktopReact/frontend/config/env.js
@@ -0,0 +1,106 @@
+
+
+const fs = require('fs');
+const path = require('path');
+const paths = require('./paths');
+
+// Make sure that including paths.js after env.js will read .env variables.
+delete require.cache[require.resolve('./paths')];
+
+const NODE_ENV = process.env.NODE_ENV;
+if (!NODE_ENV) {
+ throw new Error(
+ 'The NODE_ENV environment variable is required but was not specified.'
+ );
+}
+
+// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
+const dotenvFiles = [
+ `${paths.dotenv}.${NODE_ENV}.local`,
+ // Don't include `.env.local` for `test` environment
+ // since normally you expect tests to produce the same
+ // results for everyone
+ NODE_ENV !== 'test' && `${paths.dotenv}.local`,
+ `${paths.dotenv}.${NODE_ENV}`,
+ paths.dotenv,
+].filter(Boolean);
+
+// Load environment variables from .env* files. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set. Variable expansion is supported in .env files.
+// https://github.com/motdotla/dotenv
+// https://github.com/motdotla/dotenv-expand
+dotenvFiles.forEach(dotenvFile => {
+ if (fs.existsSync(dotenvFile)) {
+ require('dotenv-expand')(
+ require('dotenv').config({
+ path: dotenvFile,
+ })
+ );
+ }
+});
+
+// We support resolving modules according to `NODE_PATH`.
+// This lets you use absolute paths in imports inside large monorepos:
+// https://github.com/facebook/create-react-app/issues/253.
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
+// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
+// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
+// We also resolve them to make sure all tools using them work consistently.
+const appDirectory = fs.realpathSync(process.cwd());
+process.env.NODE_PATH = (process.env.NODE_PATH || '')
+ .split(path.delimiter)
+ .filter(folder => folder && !path.isAbsolute(folder))
+ .map(folder => path.resolve(appDirectory, folder))
+ .join(path.delimiter);
+
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in webpack configuration.
+const REACT_APP = /^REACT_APP_/i;
+
+function getClientEnvironment(publicUrl) {
+ const raw = Object.keys(process.env)
+ .filter(key => REACT_APP.test(key))
+ .reduce(
+ (env, key) => {
+ env[key] = process.env[key];
+ return env;
+ },
+ {
+ // Useful for determining whether we’re running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ NODE_ENV: process.env.NODE_ENV || 'development',
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example,
.
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ PUBLIC_URL: publicUrl,
+ // We support configuring the sockjs pathname during development.
+ // These settings let a developer run multiple simultaneous projects.
+ // They are used as the connection `hostname`, `pathname` and `port`
+ // in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
+ // and `sockPort` options in webpack-dev-server.
+ WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
+ WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
+ WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
+ // Whether or not react-refresh is enabled.
+ // react-refresh is not 100% stable at this time,
+ // which is why it's disabled by default.
+ // It is defined here so it is available in the webpackHotDevClient.
+ FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
+ }
+ );
+ // Stringify all values so we can feed into webpack DefinePlugin
+ const stringified = {
+ 'process.env': Object.keys(raw).reduce((env, key) => {
+ env[key] = JSON.stringify(raw[key]);
+ return env;
+ }, {}),
+ };
+
+ return { raw, stringified };
+}
+
+module.exports = getClientEnvironment;
diff --git a/DesktopReact/frontend/config/getHttpsConfig.js b/DesktopReact/frontend/config/getHttpsConfig.js
new file mode 100644
index 000000000..831426f3e
--- /dev/null
+++ b/DesktopReact/frontend/config/getHttpsConfig.js
@@ -0,0 +1,66 @@
+
+
+const fs = require('fs');
+const path = require('path');
+const crypto = require('crypto');
+const chalk = require('react-dev-utils/chalk');
+const paths = require('./paths');
+
+// Ensure the certificate and key provided are valid and if not
+// throw an easy to debug error
+function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
+ let encrypted;
+ try {
+ // publicEncrypt will throw an error with an invalid cert
+ encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
+ } catch (err) {
+ throw new Error(
+ `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
+ );
+ }
+
+ try {
+ // privateDecrypt will throw an error with an invalid key
+ crypto.privateDecrypt(key, encrypted);
+ } catch (err) {
+ throw new Error(
+ `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
+ err.message
+ }`
+ );
+ }
+}
+
+// Read file and throw an error if it doesn't exist
+function readEnvFile(file, type) {
+ if (!fs.existsSync(file)) {
+ throw new Error(
+ `You specified ${chalk.cyan(
+ type
+ )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
+ );
+ }
+ return fs.readFileSync(file);
+}
+
+// Get the https config
+// Return cert files if provided in env, otherwise just true or false
+function getHttpsConfig() {
+ const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
+ const isHttps = HTTPS === 'true';
+
+ if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
+ const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
+ const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
+ const config = {
+ cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
+ key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
+ };
+
+ validateKeyAndCerts({ ...config, keyFile, crtFile });
+ return config;
+ }
+ return isHttps;
+}
+
+module.exports = getHttpsConfig;
diff --git a/DesktopReact/frontend/config/modules.js b/DesktopReact/frontend/config/modules.js
new file mode 100644
index 000000000..52da19ac2
--- /dev/null
+++ b/DesktopReact/frontend/config/modules.js
@@ -0,0 +1,134 @@
+
+
+const fs = require('fs');
+const path = require('path');
+const paths = require('./paths');
+const chalk = require('react-dev-utils/chalk');
+const resolve = require('resolve');
+
+/**
+ * Get additional module paths based on the baseUrl of a compilerOptions object.
+ *
+ * @param {Object} options
+ */
+function getAdditionalModulePaths(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return '';
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
+ // the default behavior.
+ if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Allow the user set the `baseUrl` to `appSrc`.
+ if (path.relative(paths.appSrc, baseUrlResolved) === '') {
+ return [paths.appSrc];
+ }
+
+ // If the path is equal to the root directory we ignore it here.
+ // We don't want to allow importing from the root directly as source files are
+ // not transpiled outside of `src`. We do allow importing them with the
+ // absolute path (e.g. `src/Components/Button.js`) but we set that up with
+ // an alias.
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Otherwise, throw an error.
+ throw new Error(
+ chalk.red.bold(
+ "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
+ ' Create React App does not support other values at this time.'
+ )
+ );
+}
+
+/**
+ * Get webpack aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getWebpackAliases(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ src: paths.appSrc,
+ };
+ }
+}
+
+/**
+ * Get jest aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getJestAliases(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ '^src/(.*)$': '/src/$1',
+ };
+ }
+}
+
+function getModules() {
+ // Check if TypeScript is setup
+ const hasTsConfig = fs.existsSync(paths.appTsConfig);
+ const hasJsConfig = fs.existsSync(paths.appJsConfig);
+
+ if (hasTsConfig && hasJsConfig) {
+ throw new Error(
+ 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
+ );
+ }
+
+ let config;
+
+ // If there's a tsconfig.json we assume it's a
+ // TypeScript project and set up the config
+ // based on tsconfig.json
+ if (hasTsConfig) {
+ const ts = require(resolve.sync('typescript', {
+ basedir: paths.appNodeModules,
+ }));
+ config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
+ // Otherwise we'll check if there is jsconfig.json
+ // for non TS projects.
+ } else if (hasJsConfig) {
+ config = require(paths.appJsConfig);
+ }
+
+ config = config || {};
+ const options = config.compilerOptions || {};
+
+ const additionalModulePaths = getAdditionalModulePaths(options);
+
+ return {
+ additionalModulePaths: additionalModulePaths,
+ webpackAliases: getWebpackAliases(options),
+ jestAliases: getJestAliases(options),
+ hasTsConfig,
+ };
+}
+
+module.exports = getModules();
diff --git a/DesktopReact/frontend/config/paths.js b/DesktopReact/frontend/config/paths.js
new file mode 100644
index 000000000..a013d9aa4
--- /dev/null
+++ b/DesktopReact/frontend/config/paths.js
@@ -0,0 +1,68 @@
+
+
+const path = require('path');
+const fs = require('fs');
+const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
+const {appPublic} = require("./paths");
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebook/create-react-app/issues/637
+const appDirectory = fs.realpathSync(process.cwd());
+const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
+
+// We use `PUBLIC_URL` environment variable or "homepage" field to infer
+// "public path" at which the app is served.
+// webpack needs to know it to put the right
+
+
+
+
+
+