/ipfs-access-controller.js Secret
Last active
April 6, 2018 21:56
Using the interface proposed by https://gist.github.com/thiagodelgado111/a70394fa5d65f2871370bfe4d6c0b845 to implement simple IPFS controller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Inheritance design not necessary | |
class IPFSAccessController extends AccessController { | |
constructor(address, ipfs, keystore) { | |
super(keystore) | |
this._ipfs = ipfs; | |
this._address = address; | |
this._access = { | |
admin: [], | |
read: [], | |
write: [] | |
} | |
} | |
async load(address) | |
async save() | |
async grantPermission(access, key) { // Call external service, a smart-contract, whatever | |
// Copied from the current access-controller.js implementation | |
switch (access) { | |
case 'admin': | |
this._access.admin.push(key) | |
break | |
case 'write': | |
this._access.write.push(key) | |
break | |
case 'read': | |
this._access.read.push(key) | |
break | |
default: | |
break | |
} | |
} | |
async revokePermission(permission, key, args) { | |
const without = (arr, e) => { | |
const reducer = (res, val) => { | |
if (val !== key) | |
res.push(val) | |
return res | |
} | |
return arr.reduce(reducer, []) | |
} | |
// if(!Object.keys(this._access).includes(access)) | |
// throw new Error(`unknown access level: ${access}`) | |
// if (this._access[access].includes(key)) | |
// this._access[access] = without(this._access[access], key) | |
switch (access) { | |
case 'admin': | |
this._access.admin = without(this._access.admin, key) | |
break | |
case 'write': | |
this._access.write = without(this._access.write, key) | |
break | |
case 'read': | |
this._access.read = without(this._access.read, key) | |
break | |
default: | |
break | |
} | |
} | |
async isAllowed(permission, key) { | |
// omitted for simplicity, same implementation as nowadays, we could probably also cache it so we dont try to fetch it | |
await ensureIsLoaded(this._address) | |
if (!this._access[permission]) { // return false? | |
throw new Error('Permission not found') | |
} | |
return Promise.resolve( | |
this._access[permission].includes('*') || this._access[permission].includes(entry.key) | |
) | |
} | |
// Use IPFS controller, external service, smart-contract, orbit-db-permission-store, etc. | |
async isValidEntry(entry) { | |
// omitted for simplicity, same implementation as nowadays, we could probably also cache it so we dont try to fetch it | |
await ensureIsLoaded(this._address) | |
if (!(this._access.write.includes('*') || this._access.write.includes(entry.key)) { | |
throw new Error('Not allowed') | |
} | |
return Promise.resolve( | |
// Ideally we would get the entry ready to be used or use an encoding function here | |
this.keystore.verify(entry.signature, entry.key, Buffer.from(JSON.stringify(entry))) | |
) | |
} | |
/* | |
* Even this method could be implemented by the concrete class then nothing would be derived from a base class | |
* Here just to illustrate the proposed interface | |
*/ | |
async signEntry(entry) { | |
// Signature implemented by the "signer", maybe we should just call it "wallet" or "provider" | |
entry.signature = await this.keystore.sign(Buffer.from(JSON.stringify(entry))) | |
entry.key = this.keystore.getPublicKey(); | |
entry.extra = Date.now() // Whatever | |
return entry | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment