+* @file Strapp File System
+* @author Jordan Lavatai, Ken Grimes
+* @version 0.0.1
+* @license AGPL-3.0
+* @copyright August 2017 - Ken Grimes, Jordan Lavatai
+* @summmary File system implementation for a strapp node
+*/
+import strapp from './strapp.js'
+import localforage from 'localforage'
+localforage.config({
+ name: 'strapp'
+})
+/** extend localforage with an assign operation */
+localforage.assignItem = (path, data) => localforage.getItem(path).then((fdata) => localforage.setItem(path, fdata ? Object.assign(fdata, data) : data))
+localforage.getOrSetItem = (path, defaults) => localforage.getItem(path).then((data) => data === null ? localforage.setItem(path, defaults) : Promise.resolve(data))
+
+const _bootTime = new Date()
+
+const StrappFile = (() => {
+ class StrappFile extends Object {
+ constructor(...props) {
+ super()
+ return Object.assign(this, new.target.literal(), ...props)
+ }
+ static literal(...props) {
+ return Object.assign(Object.create(null), this.defaults, ...props)
+ }
+ static parse(fileLiteral, ...props) {
+ switch(fileLiteral.type) {
+ case 'application/JSON':
+ return new StrappJSON(fileLiteral, ...props)
+ case 'strapp/directory':
+ return new StrappDirectory(fileLiteral, ...props)
+ case 'strapp/file':
+ default:
+ return new StrappFile(fileLiteral, ...props)
+ }
+ }
+ resolveRequest(method, pubKey, data, locStack) {
+ if (!locStack)
+ return Promise.reject(400)
+ if (locStack.length > 0)
+ return Promise.reject(404)
+ let reqPerms = 0
+ switch(method) {
+ case 'OPTIONS':
+ return this.resolveClientPerms(pubKey).then(
+ (perms) => {
+ let allow = ['OPTIONS']
+ if (perms & 0x9)
+ allow.push('CONNECT')
+ if (perms & 0x2)
+ allow.push('DELETE').push('PUT').push('POST')
+ if (perms & 0x4)
+ allow.push('GET').push('HEAD')
+ return Promise.resolve(allow.join(', '))
+ },
+ (err) => Promise.reject(500)
+ )
+ default:
+ return Promise.reject(405)
+ case 'PUT':
+ case 'POST':
+ case 'DELETE':
+ reqPerms = 0x2
+ break
+ case 'GET':
+ case 'HEAD':
+ reqPerms = 0x4
+ break
+ case 'CONNECT':
+ reqPerms = 0x9
+ break
+ }
+ return this.resolveClientPerms(pubKey)
+ .then((perms) => { console.log(`got ${perms} for ${reqPerms} in ${this.path}, owned by ${this.owner} with ${this.perms.toString(16)}`)
+ return Promise.resolve(perms)})
+ .then(
+ (perms) => ((reqPerms & perms) === reqPerms) ?
+ this[method](pubKey, data) : Promise.reject(401),
+ (err) => Promise.reject(500))
+ }
+ resolveClientPerms(pubKey) {
+ if (!pubKey || pubKey === '')
+ return Promise.resolve((this.perms >>> 12) & 0xF)
+ return localforage.getItem(`acct/${this.owner}`).then((fData) => {
+ if (fData && 'pubKey' in fData && fData.pubKey === pubKey)
+ return Promise.resolve((this.perms >>> 8) & 0xF)
+ return localforage.getItem(`acct/${pubKey}`).then((account) => {
+ if (account && account.groups &&
+ account.groups.some((group) => group === this.group))
+ return Promise.resolve((this.perms >>> 4) & 0xF)
+ return Promise.resolve(this.perms & 0xF)
+ })
+ })
+ }
+ HEAD(pubKey) {
+ return Promise.resolve()
+ }
+ GET(pubKey) {
+ return localforage.getItem(this.path)
+ }
+ PUT(pubKey, data) {
+ return localforage.setItem(this.path, data)
+ }
+ POST(pubKey, data) {
+ return localforage.getItem(this.path).then(
+ (fData) => localforage.setItem(this.path, fData + data))
+ }
+ DELETE(pubKey) {
+ return localforage.removeItem(this.path)
+ }
+ CONNECT(pubKey) { //TODO
+ return Promise.reject(501)
+ }
+ TRACE(opt) {
+ }
+ PATCH(opt) {
+ }