Skip to content

Instantly share code, notes, and snippets.

@thiagodelgado111
Last active April 6, 2018 21:56
Show Gist options
  • Save thiagodelgado111/262ff49b149743ff388ff4295e4674fa to your computer and use it in GitHub Desktop.
Save thiagodelgado111/262ff49b149743ff388ff4295e4674fa to your computer and use it in GitHub Desktop.
Using the interface proposed by https://gist.github.com/thiagodelgado111/a70394fa5d65f2871370bfe4d6c0b845 to implement simple IPFS controller
// 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