/**
- * @file Shared API
+ * @file Bootstrapping API
* @author Jordan Lavatai and Ken Grimes
* @version 0.0.1
- * @license APGL-3.0
+ * @license AGPL-3.0
* @copyright Strapp.io
*/
-const dlog = (msg) => console.log(msg)
-
-/***********************/
-/** Helper functions **/
-/***********************/
-
-/* SDP Interop helper functions to be used by beginRTCOffer and beginRTCAnswer */
-
-/** @func Determines the multimedia signaling protocol for the given session description
- * @desc Does some basic duck typing to determine the type of Session Description
- * @arg {Object} Session Description Object
- * @return {String} Returns 'planB' if Session Description is planB, 'Unified' if
- * Session Description is Unified
- */
-function determineSessionDescription(sessionDescription) {
-}
-
-/** @func Converts a planB session description to Unified session description
- * @arg {Object} Session Description Object
- * @return {Object} PlanB Session Description
- */
-function toUnified(sessionDescription) {
-}
-
-/** @func Converts a Unified session description to planB session description
- * @arg {Object} Session Description Object
- * @return {Object} PlanB Session Description
- */
-function toPlanB(sessionDescription) {
-}
-
-/* WebSocket wielder helper functions */
-
-/* Function for setting up webSocket wielders message handler */
-/* TBD */
-/* TBD */
-
-/* SDP Negotiation helper functions */
-
-/* addRemoteIceCandidate() */
-/* addIceCandidateCreationHandler(callback for sending?) */
-/* handleIceRequest() - WebSpocketless entity specific */
-
-
-/***********************/
-/** Exposed functions **/
-/***********************/
-
-/** @func Attempts to create a websocket
- * @desc If user agent supports web sockets, attempt to create a websocket
- * with given domain
- * @arg {String} domain - ip address or domain name of other end of websocket
- * @return {Boolean} returns true if successful, false if unsucessful
- */
-export function createWebSocket(domain) {
-
-}
+import fs from "fileManager"
/** @func Returns public key for the user
* @desc Attempts to find a stored key. If unsucessful, ask user for key. If user
* @options specif
* @return {Object} cryptoKey object
*/
-export function resolveKey() {
-
+function resolveKey() {
+ return new Promise( (resolve, reject) => {
+ /* See if publicKey has been generated before */
+ const publicKey = fs.strappID
+ if (publicKey === '') {
+ resolve(generateKey())
+ }
+ else {
+ resolve(publicKey)
+ }
+ })
}
-/** @func Begins the SDP handshake process as the offerer
- * @desc
- *
- *
- */
-export function beginRTCOffer() {
-}
+/* Init FileSystem */
+fs.initFileSystem()
-/** @func Begins the SDP handshake process as the answerer
- * @desc
- *
- *
- */
-export function beginRTCAnswer() {
-}
+/* Find or generate key */
+let key = resolveKey()
+
+/* Auth */
+/* Authorization-header: Strapp pubkey (no answer)*/
+/* Determine answer, add answer to "." */
+
+
+/* Setup hardcoded files e.g. "..", ".", "accounts", "ice", "sdp", "log", "run" */
+/* Add the files to the filesystem only if they dont already exist /*
+
+/* Connect to host */
+
+
-/** @func Generic way to message host from client
- * @desc tbd
- * @arg {Object} data object to be sent
- */
-export function sendHostData(data) {
-}
-/** @func Generic way to message client from host
- * @desc tbd
- * @arg {Object} data object to be sent
- */
-export function sendClientData(data){
-}
--- /dev/null
+/**
+ * @file Management for bootstrapp cryptography
+ * @desc Makes keys, encrypts and decrypts messages
+ *
+ * @author Jordan Lavatai and Ken Grimes
+ * @version 0.0.1
+ * @license AGPL-3.0
+ * @copyright Strapp.io
+ */
+
+import {setItem, getItem} from "localForage"
+
+/** @func Generates a CryptoKey and returns a SHA-256 client key
+ * @desc Utilizes Web Crypto to create a CryptoKey using RSA specification.
+ * Stores both public and private representation of the key and returns
+ * the public key
+ * @return {String} clientKey
+ */
+function generateKey() {
+ crypto.subtle.generateKey(
+ { name:'RSA-OAEP',
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {name: "SHA-256"}
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then((cryptoKey) => {
+ /* TODO: Do we need to store the private key as well? */
+ crypto.subtle.exportKey('jwk', cryptoKey)
+ .then((exportedKey) => {
+ setItem('publicKey', exportedKey.publicKey)
+ setItem('privateKey', exportedKey.privateKey)
+ console.log('public key is' + getItem('publicKey'))
+ console.log('private key is' + getItem('privateKey'))
+ return exportedKey.publicKey
+ })
+ })
+}
+
+/** @func Encrypts data with a public key
+ * @desc
+ * @arg {String} Public Key
+ * @return {Object} The encrypted data
+ */
+function encryptData(publicKey, data) {
+
+}
+/** @func Decrypts data with a private key
+ * @desc
+ * @arg {String} Private key to decrypt data
+ * @return {Object} The decrypted data
+ */
+function decryptData(privateKey, data) {
+}
+
+function
--- /dev/null
+/**
+ * @file File System Interface
+ * @desc Provides basic file commands for interacting with Strapp
+ * file system as well as storage (and backups) of file system
+ * @author Jordan Lavatai and Ken Grimes
+ * @version 0.0.1
+ * @license AGPL-3.0
+ * @copyright Strapp.io
+ */
+
+import localforage from "localforage"
+import StrappPeerConnection from "strappPeerConnection"
+
+/* File constructor */
+class File extends Object {
+ constructor(...props) {
+ super()
+ return Object.assign(this, new.target.defaults, ...props)
+ }
+ get() {
+ return this.data
+ }
+ post(postedData) {
+ this.data += postedData
+ this.lastModified = new Date()
+ }
+ put(putData) {
+ this.data = putData
+ this.lastModified = new Date()
+ }
+ delete() {
+ this.data = ''
+ this.lastModified = new Date()
+ }
+ connect() {
+
+ }
+ options(publicKey) {
+ return this.availPermissions(publicKey)
+ }
+}
+/* TODO: Continue to flesh this out */
+File.defaults = {
+ name: '',
+ data: '',
+ mode: {},
+ size: 0
+ //lastModified: new Date()?
+ //lastAccessed: new Date()?
+
+}
+
+
+/* Filesystem maintains the current session memory for the strapp instance. Files can be
+ created and killed from the filesystem without leveraging localForage. Files that are
+ in the filesystem can be stored to localForage while files that are in localForage can be loaded
+ to the filesystem. When a Filesystem is first intialized, it attempts to get its strappID it populates itself from localForage and
+ overwrites any files in its current memory. Files that have restore() as a property (which will be some method needed to
+ make the file functions e.g. strappPeerConnections will restore() themselves lazily, i.e. when they are needed.*/
+
+ /* TODO: Should it be possible to create/preserve/destroy a file to both localForage and fileSystem? (same time) */
+ /* TODO: Should initFileSystem not overwrite files? */
+
+/* These are the default files on all file systems */
+let defaultFiles = [ "..", ".", "accounts", "ice", "log", "run" ]
+
+
+/* TODO: Protect data via closures? */
+const fs = {
+ /* TODO: What if files are added to file system before init is is called? */
+ initFileSystem(){
+ this.db = localforage.createInstance({ name: "database" })
+ /* Iterate through all files on localforage, adding them to FileSystem
+ and calling their restore methods */
+ this.db.iterate( (value, key, n) => {
+ /* just btw, return !undefined to exit early */
+ this.loadFile(key, true)
+
+ }).catch( (err) => {
+ console.log(`error: ${err} when iterating through localForage during initFileSystem`)
+ })
+ /* Add the hardcoded default files if they dont already exist */
+ /* Restore these files --> need the private/public key*/
+ initialFiles.map( (val, idx, array) => {
+ if (this.fileExists(val)) {
+ let file = this.getFile(val)
+ let restoreProp = file['restore']
+ if (restoreProp === undefined && typeof restoreFx === 'function') {
+ //restore file
+ }
+ /* Else don't do anything, file exists in FS and doesnt need to be restored */
+ }
+ else {
+ /* TODO: Remove checking for every file --> although its only for the default files which
+ will probably be a low number. Still, unnecessary. Could make initialFiles a
+ Map object with fileType in it and switch(val.fileType) */
+ if (val === '..') {
+ let file = new StrappPeerConnection()
+ /* Connect with host */
+ }
+ else {
+ /* Each default file is going to have specific permissions, */
+ let filedata = new File()
+ filedata.name = val
+ filedata.mode =
+ this.createFile(val,)
+ }
+ }
+
+ })
+
+ },
+
+ fileExists(filename) {
+ return this.files[filename] === undefined ? false : true
+ },
+
+ /* Create a file in the file system, if specified overwrites any file that is already there
+ else does nothing */
+ createFile(filename, filedata, overwrite = false){
+ filedata.name = filename
+ if (this.files[filename] === undefined) {
+ this.files[filename] = filedata
+ }
+ else {
+ if (overwrite) {
+ console.log(`Overwriting ${filename}`)
+ this.files[filename] = filedata
+ }
+ else {
+ console.log(`Didn't overwrite file so nothing happened`)
+ }
+ }
+ },
+
+ /* Get a file from browser session memory */
+ /* TODO: Option to get from localForage? */
+ getFile(filename) {
+ return this.files[filename]
+ },
+
+ /* Save a file to file system*/
+ saveFile(filename, filedata) {
+ /* TODO: Determine if file to be saved is of saveable nature e.g. SPC's cant really be saved */
+ this.db.setItem(filename, filedata)
+ },
+
+ /* Delete file from localForage */
+ removeFile(filename) {
+ this.db.removeItem(filename)
+ },
+
+ /* Delete a file from file system */
+ killFile(filename) {
+ delete this.files[filename]
+
+ },
+
+ /* Store file in file system to localForage */
+ storeFile(filename) {
+ this.db.setItem(filename, this.files[filename].filedata)
+ },
+
+ /* Load file from localForage to file system */
+ loadFile(filename, overwrite = false) {
+ let filedata = this.db.getItem(filename)
+ filedata = filedata.restore === undefined ? filedata : filedata.restore()
+ this.createFile(filename, filedata, overwrite)
+ },
+
+ saveFileSystem() {
+ /* TODO: save all files in filesystem to localforage */
+ },
+ db: {},
+ files: {}
+
+}
+
+/* File System API */
+
+
+/* Load file system from localStorage/indexedDB if strapp.js is running on a host */
+function loadFileSystem(){
+
+}
+
+/* Store file system before shutting down if strapp.js is running on a host- */
+function storeFileSystem(){}
+
+
+
+/* addFile - adds a created file to a file */
+//@arg fileType - what to set the type property
+//@arg fileData - what to set the data property
+//@arg filePos - where to create the file
+
+/* Determine if a publicKey has permissions to execute methods
+
+/* rm - Delete file */
+
+/* ls - display file contents */
+ //open file
+//return all of file files
+
+/* cat - display file data */
+//return file data
+
+/* open - Open file */
+ //traverse to file path
+/* perm - display file permissions (if you have permissions) */
+/* find - find a file */
+//@arg fileToFind
+/* stat - info about a file */
+//@arg path - path to the file
+/* exists - determine if a file contains a file */
+//@arg {String} searchedFile - file to be searched
+//@arg {String} fileName
+//@arg {Number} Depth to look
+//@return {Boolean} true if exists, false if doesn't
+
+
+
+
+
--- /dev/null
+/**
+ * @file File System Interface
+ * @desc Provides basic file commands for interacting with Strapp
+ * file system as well as storage (and backups) of file system
+ * @author Jordan Lavatai and Ken Grimes
+ * @version 0.0.1
+ * @license AGPL-3.0
+ * @copyright Strapp.io
+ */
+
+import localforage from "localforage"
+import StrappPeerConnection from "strappPeerConnection"
+
+/* File constructor */
+class File extends Object {
+ constructor(...props) {
+ super()
+ return Object.assign(this, new.target.defaults, ...props)
+ }
+ get() {
+ return this.data
+ }
+ post(postedData) {
+ this.data += postedData
+ this.lastModified = new Date()
+ }
+ put(putData) {
+ this.data = putData
+ this.lastModified = new Date()
+ }
+ delete() {
+ this.data = ''
+ this.lastModified = new Date()
+ }
+ connect() {
+
+ }
+ options(publicKey) {
+ return this.availPermissions(publicKey)
+ }
+}
+/* TODO: Continue to flesh this out */
+File.defaults = {
+ name: '',
+ data: '',
+ mode: {},
+ size: 0
+ //lastModified: new Date()?
+ //lastAccessed: new Date()?
+
+}
+
+
+/* Filesystem maintains the current session memory for the strapp instance. Files can be
+ created and killed from the filesystem without leveraging localForage. Files that are
+ in the filesystem can be stored to localForage while files that are in localForage can be loaded
+ to the filesystem. When a Filesystem is first intialized, it attempts to get its strappID it populates itself from localForage and
+ overwrites any files in its current memory. Files that have restore() as a property (which will be some method needed to
+ make the file functions e.g. strappPeerConnections will restore() themselves lazily, i.e. when they are needed.*/
+
+ /* TODO: Should it be possible to create/preserve/destroy a file to both localForage and fileSystem? (same time) */
+ /* TODO: Should initFileSystem not overwrite files? */
+
+/* These are the default files on all file systems */
+let defaultFiles = [ "..", ".", "accounts", "ice", "log", "run" ]
+
+
+/* TODO: Protect data via closures? */
+const fs = {
+ /* TODO: What if files are added to file system before init is is called? */
+ initFileSystem(){
+ this.db = localforage.createInstance({ name: "database" })
+ /* Iterate through all files on localforage, adding them to FileSystem
+ and calling their restore methods */
+ this.db.iterate( (value, key, n) => {
+ /* just btw, return !undefined to exit early */
+ this.loadFile(key, true)
+
+ }).catch( (err) => {
+ console.log(`error: ${err} when iterating through localForage during initFileSystem`)
+ })
+ /* Add the hardcoded default files if they dont already exist */
+ /* Restore these files --> need the private/public key*/
+ initialFiles.map( (val, idx, array) => {
+ if (this.fileExists(val)) {
+ let file = this.getFile(val)
+ let restoreProp = file['restore']
+ if (restoreProp === undefined && typeof restoreFx === 'function') {
+ //restore file
+ }
+ /* Else don't do anything, file exists in FS and doesnt need to be restored */
+ }
+ else {
+ /* TODO: Remove checking for every file --> although its only for the default files which
+ will probably be a low number. Still, unnecessary. Could make initialFiles a
+ Map object with fileType in it and switch(val.fileType) */
+ if (val === '..') {
+ let file = new StrappPeerConnection()
+ /* Connect with host */
+ }
+ else {
+ /* Each default file is going to have specific permissions, */
+ let filedata = new File()
+ filedata.name = val
+ filedata.mode =
+ this.createFile(val,)
+ }
+ }
+
+ })
+
+ },
+
+ fileExists(filename) {
+ return this.files[filename] === undefined ? false : true
+ },
+
+ /* Create a file in the file system, if specified overwrites any file that is already there
+ else does nothing */
+ createFile(filename, filedata, overwrite = false){
+ filedata.name = filename
+ if (this.files[filename] === undefined) {
+ this.files[filename] = filedata
+ }
+ else {
+ if (overwrite) {
+ console.log(`Overwriting ${filename}`)
+ this.files[filename] = filedata
+ }
+ else {
+ console.log(`Didn't overwrite file so nothing happened`)
+ }
+ }
+ },
+
+ /* Get a file from browser session memory */
+ /* TODO: Option to get from localForage? */
+ getFile(filename) {
+ return this.files[filename]
+ },
+
+ /* Save a file to file system*/
+ saveFile(filename, filedata) {
+ /* TODO: Determine if file to be saved is of saveable nature e.g. SPC's cant really be saved */
+ this.db.setItem(filename, filedata)
+ },
+
+ /* Delete file from localForage */
+ removeFile(filename) {
+ this.db.removeItem(filename)
+ },
+
+ /* Delete a file from file system */
+ killFile(filename) {
+ delete this.files[filename]
+
+ },
+
+ /* Store file in file system to localForage */
+ storeFile(filename) {
+ this.db.setItem(filename, this.files[filename].filedata)
+ },
+
+ /* Load file from localForage to file system */
+ loadFile(filename, overwrite = false) {
+ let filedata = this.db.getItem(filename)
+ filedata = filedata.restore === undefined ? filedata : filedata.restore()
+ this.createFile(filename, filedata, overwrite)
+ },
+
+ saveFileSystem() {
+ /* TODO: save all files in filesystem to localforage */
+ },
+ db: {},
+ files: {}
+
+}
+
+/* File System API */
+
+
+/* Load file system from localStorage/indexedDB if strapp.js is running on a host */
+function loadFileSystem(){
+
+}
+
+/* Store file system before shutting down if strapp.js is running on a host- */
+function storeFileSystem(){}
+
+
+
+/* addFile - adds a created file to a file */
+//@arg fileType - what to set the type property
+//@arg fileData - what to set the data property
+//@arg filePos - where to create the file
+
+/* Determine if a publicKey has permissions to execute methods
+
+/* rm - Delete file */
+
+/* ls - display file contents */
+ //open file
+//return all of file files
+
+/* cat - display file data */
+//return file data
+
+/* open - Open file */
+ //traverse to file path
+/* perm - display file permissions (if you have permissions) */
+/* find - find a file */
+//@arg fileToFind
+/* stat - info about a file */
+//@arg path - path to the file
+/* exists - determine if a file contains a file */
+//@arg {String} searchedFile - file to be searched
+//@arg {String} fileName
+//@arg {Number} Depth to look
+//@return {Boolean} true if exists, false if doesn't
+
+
+
+
+
--- /dev/null
+/**
+ * @file Messaging module providing capability for files to communicate with each other
+ * @author Jordan Lavatai and Ken Grimes
+ * @version 0.0.1
+ * @license AGPL-3.0
+ * @copyright Strapp.io
+ */
+
+/** Remote Peer States:
+ unintialized
+
+
+/* SPC default object */
+class StrappPeerConnection extends File {
+ GET() {
+ }
+ POST() {
+ }
+ CONNECT() {
+ }
+ OPTIONS() {
+ }
+ DELETE() {
+ }
+
+}
+
+
+strappPeerConnection.defaults = Object.assign({}, File.defaults, {
+ state: '',
+ messageCount: 0,
+ messageHandler: new Map(), /* TODO: seperate handling? */
+ remotePeer: {
+ bestConnectionType: '',
+ state: '',
+ peerID: '' /* clientID of Peer* /
+ }
+}
+
+/* GET - gets the data (queued messages) from a spc */
+/* POST - sends a msg through a spc to the remote peer */
+/* CONNECT - Tries to establish a connection with an spc */
+/* local or remote peer of the spc? */
+ /* Local is part of uri, make it remote*/
+
+/* File System */
+/* Convert entire file system into json objects that can be read into memory */
+
+
+/* Send */
+/* Receive */
+/* Reconnect WebRTC */
+/* Reconnect WS */
+/* Determine remote peers bestConnectionType */
+/* Restablish connection */
+
+
+/** @func Send a message to the remote peer
+ * @desc
+ *
+ * @arg {Object} message - message in LMKID format, except no message ID yet
+ * @this {Object} - Refers to the SPC that is calling send
+ * @return {Object} - Promise for the response from the send message
+ */
+function send(message) {
+ /* Determine if 'this' is a SPC object */
+
+
+ /* 'send data' means to create a strapp protocol message and send it over whichever
+ transmission channel is available */
+ switch (this.state) {
+ case 'unintialized':
+ case 'offline':
+ if (this.establishConnection(clientKey, data)) {
+ send(clientKey, data)
+ }
+ else {
+ storeMessage(this, message)
+ }
+
+ break
+ case 'disconnected':
+ this.reestablishConnection(clientKey, data)
+ /* Store the message */
+ /* Fail if reconnection attempt fails */
+ break
+ case 'polling': {
+ /* does remote peer have the ability to upgrade? */
+ /* If so, attempt to upgrade */
+ /* If upgrade fails, retry the send method else send via polling */
+ break
+ }
+ case 'webSocket': {
+ /* does remote peer have the ability to upgrade? */
+ /* If so, attempt to upgrade */
+ /* If upgrade fails, retry the send method else send via polling */
+ break
+ }
+ case 'webRTC': {
+ /* If remote peer is connected, send data */
+ /* Else Attemp to fix connection, if connection is dead, set this.state and try this again. Will
+ Enter the 'disconnected' state */
+ break
+ }
+
+ }
+}
+
+
+
+/** @func Attempts to connect the local peer to the remote peer
+ * @desc
+ *
+ * @ret {boolean} True if successful, false if not
+ */
+function establishSPC() {
+
+}
+
+/** @func Attempts to reconnect the local peer to the remote peer
+ * @desc This function assumes that the remotePeer property for the SPC object has
+ * been elevated to a status higher than uninitialized.
+ *
+ * @ret {boolean} True if successful, false if not
+ */
+function reestablishSPC() {
+ /* If successful, send all the cached messages that were saved when connection was down */
+}
+
+
+/** @func Stores the message
+ * @desc
+ *
+ */
+function storeMessage() {
+}
+
+/** @func Determines the multimedia signaling protocol for the given session description
+ * @desc Does some basic duck typing to determine the type of Session Description
+ * @arg {Object} Session Description Object
+ * @return {String} Returns 'planB' if Session Description is planB, 'Unified' if
+ * Session Description is Unified
+ */
+function determineSessionDescription(sessionDescription) {
+}
+
+/** @func Converts a planB session description to Unified session description
+ * @arg {Object} Session Description Object
+ * @return {Object} PlanB Session Description
+ */
+function toUnified(sessionDescription) {
+}
+
+/** @func Converts a Unified session description to planB session description
+ * @arg {Object} Session Description Object
+ * @return {Object} PlanB Session Description
+ */
+function toPlanB(sessionDescription) {
+}
--- /dev/null
+/**
+ * @file Strapp Protocol Manager
+ * @author Jordan Lavatai and Ken Grimes
+ * @version 0.0.1
+ * @license AGPL-3.0
+ * @copyright Strapp.io
+ */
+
+import send from 'spc'
+
+/* KLMID == Key Location Method msgID Data */
+/* Convert from KLMID to HTTP */
+/* Convert from HTTP to KLMID */
+/* Parse KLMID -> Execute method based on location */
+/* Convert Object with KLMID keys to a string */
+
+/** @func Parse the strapp protocol string
+ * @desc KLMID stands for Location Key Method ID Data
+ * [Optional] Key is the clientKey that is used to authorize the method
+ * If not specified, this message will not have any authorizations
+ * [Optional] Location is the location of the target file that the method will execute upon
+ * If not specified, target file is the current file
+ * [Required] Method is one of the file commands available
+ * [Required] ID is the message ID, used when multiple messages are being sent and received
+ * [Optional] Data is a parameter for the method e.g. PUT will replace the target files data property
+ *
+ * An unincluded message part needs to be indicated by a whitespace, i.e. ' ' i.e. /u{0020}.
+ * This function is mainly called by a SPCs receive event that processes every message that a SPC
+ * receives
+ * @arg {String} msg - String conforming to the strapp protocol
+ * @return {Object} - Parsed object with keys corresponding to segments of strapp Protocol
+ */
+function parseSPM(msg) {
+ /* if no location, then call the method in LMKID on the local file, i.e. "." */
+}