Skip to content
This repository was archived by the owner on May 19, 2023. It is now read-only.

Commit c861971

Browse files
authored
Implement backup per did feature (#53)
* Provider layer * Service layer * Client layer * Use authManager to getBackup
1 parent cc004e9 commit c861971

File tree

13 files changed

+231
-3
lines changed

13 files changed

+231
-3
lines changed

modules/ipfs-cpinner-client/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ console.log(`Used: ${storage.used}`)
7979
console.log(`Available: ${storage.available}`)
8080
```
8181

82+
### Get backup information
83+
84+
```typescript
85+
import DataVaultWebClient from '@rsksmart/ipfs-cpinner-client'
86+
87+
const client = new DataVaultWebClient({ serviceUrl, did, rpcPersonalSign, serviceDid })
88+
89+
const backup = await client.getBackup()
90+
91+
console.log('This is the keys and cids you have stored in the DV')
92+
console.log(backup)
93+
```
94+
8295
### Create
8396

8497
```typescript

modules/ipfs-cpinner-client/src/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AUTHENTICATION_ERROR, MAX_STORAGE_REACHED, SERVICE_MAX_STORAGE_REACHED,
55
import {
66
CreateContentPayload, CreateContentResponse,
77
DeleteTokenPayload, GetContentPayload, Config,
8-
SwapContentPayload, SwapContentResponse, GetContentResponsePayload, StorageInformation
8+
SwapContentPayload, SwapContentResponse, GetContentResponsePayload, StorageInformation, Backup
99
} from './types'
1010

1111
export default class {
@@ -56,6 +56,18 @@ export default class {
5656
.catch(this.errorHandler)
5757
}
5858

59+
getBackup (): Promise<Backup> {
60+
const { serviceUrl } = this.config
61+
62+
return this.authManager.getAccessToken()
63+
.then(accessToken => axios.get(
64+
`${serviceUrl}/backup`,
65+
{ headers: { Authorization: `DIDAuth ${accessToken}` } })
66+
)
67+
.then(res => res.status === 200 && res.data)
68+
.catch(this.errorHandler)
69+
}
70+
5971
create (payload: CreateContentPayload): Promise<CreateContentResponse> {
6072
const { content, key } = payload
6173
const { serviceUrl } = this.config

modules/ipfs-cpinner-client/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type DeleteTokenPayload = { key: string, id?: string }
88
export type SwapContentPayload = { key: string, content: string, id?: string }
99
export type SwapContentResponse = { id: string }
1010
export type StorageInformation = { used: number, available: number }
11+
export type Backup = { key: string, id: string }[]
1112

1213
export type Config = {
1314
serviceUrl: string
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { IpfsPinnerProvider } from '@rsksmart/ipfs-cpinner-provider'
2+
import { deleteDatabase, resetDatabase, setupDataVaultClient, startService, testTimestamp } from './util'
3+
import { Server } from 'http'
4+
import { Connection } from 'typeorm'
5+
import MockDate from 'mockdate'
6+
import localStorageMockFactory from './localStorageMockFactory'
7+
8+
describe('get backup', function (this: {
9+
server: Server,
10+
dbConnection: Connection,
11+
ipfsPinnerProvider: IpfsPinnerProvider,
12+
serviceUrl: string,
13+
serviceDid: string
14+
}) {
15+
const dbName = 'get-backup.sqlite'
16+
17+
beforeAll(async () => {
18+
const { server, serviceUrl, ipfsPinnerProvider, dbConnection, serviceDid } = await startService(dbName, 4608)
19+
this.server = server
20+
this.ipfsPinnerProvider = ipfsPinnerProvider
21+
this.dbConnection = dbConnection
22+
this.serviceUrl = serviceUrl
23+
this.serviceDid = serviceDid
24+
})
25+
26+
afterAll(async () => {
27+
this.server.close()
28+
await deleteDatabase(this.dbConnection, dbName)
29+
})
30+
31+
beforeEach(() => {
32+
MockDate.set(testTimestamp)
33+
global.localStorage = localStorageMockFactory()
34+
})
35+
36+
afterEach(async () => {
37+
MockDate.reset()
38+
await resetDatabase(this.dbConnection)
39+
})
40+
41+
test('should return an empty object if no data saved', async () => {
42+
const { dataVaultClient } = await setupDataVaultClient(this.serviceUrl, this.serviceDid)
43+
44+
const backup = await dataVaultClient.getBackup()
45+
46+
expect(backup).toEqual([])
47+
})
48+
49+
test('should return the saved data', async () => {
50+
const { dataVaultClient, did } = await setupDataVaultClient(this.serviceUrl, this.serviceDid)
51+
52+
const key1 = 'TheKey1'
53+
const key2 = 'TheKey2'
54+
const id1 = await this.ipfsPinnerProvider.create(did, key1, 'some content')
55+
const id2 = await this.ipfsPinnerProvider.create(did, key1, 'another content for same did')
56+
const id3 = await this.ipfsPinnerProvider.create(did, key2, 'another content for another did')
57+
58+
const backup = await dataVaultClient.getBackup()
59+
60+
expect(backup).toEqual([
61+
{ key: key1, id: id1 },
62+
{ key: key1, id: id2 },
63+
{ key: key2, id: id3 }
64+
])
65+
})
66+
})

modules/ipfs-cpinner-provider/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ const deleted: boolean = await ipfsPinnerProvider.delete(did, key, cid) // cid c
7373
const availableStorage: number = await ipfsPinnerProvider.getAvailableStorage(did) // return the amount of bytes available to store value associated to the given did
7474
7575
const usedStorage: number = await ipfsPinnerProvider.getUsedStorage(did) // return the amount of bytes used to store value associated to the given did
76+
77+
const didBackup: Backup = await ipfsPinnerProvider.getBackup(did) // return an array containing all the keys and cids created by the given did
7678
```
7779

7880
See our [documentation](https://developers.rsk.co/rif/identity/) for advanced usage.

modules/ipfs-cpinner-provider/src/IpfsPinnerProvider.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { MAX_STORAGE_REACHED } from './constants'
22
import {
3-
Content, CID, DID, IpfsPinner, Key, MetadataManager, IpfsClient, SavedContent
3+
Content, CID, DID, IpfsPinner, Key, MetadataManager, IpfsClient, SavedContent, Backup
44
} from './types'
55

66
export default class IpfsPinnerProvider {
@@ -81,6 +81,10 @@ export default class IpfsPinnerProvider {
8181
return this.metadataManager.getUsedStorage(did)
8282
}
8383

84+
getBackup (did: DID): Promise<Backup> {
85+
return this.metadataManager.getBackupByDid(did)
86+
}
87+
8488
private async deleteByCid (did: DID, key: Key, cid: CID): Promise<boolean> {
8589
const removed = await this.metadataManager.delete(did, key, cid)
8690
if (removed) return this.ipfsPinner.unpin(cid)

modules/ipfs-cpinner-provider/src/MetadataManager.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Repository } from 'typeorm'
22
import IpfsMetadata from './entities/ipfs-metadata'
3-
import { CID, MetadataManager, DID, Key } from './types'
3+
import { CID, MetadataManager, DID, Key, Backup } from './types'
44

55
export default class implements MetadataManager {
66
// eslint-disable-next-line no-useless-constructor
@@ -53,4 +53,11 @@ export default class implements MetadataManager {
5353
select: ['contentSize']
5454
}).then((entries: { contentSize: number }[]) => entries.map(e => e.contentSize).reduce((a, b) => a + b, 0))
5555
}
56+
57+
getBackupByDid (did: string): Promise<Backup> {
58+
return this.repository.find({
59+
where: { did },
60+
select: ['key', 'cid']
61+
}).then((entries: IpfsMetadata[]) => entries.map(({ key, cid }) => ({ key, id: cid })))
62+
}
5663
}

modules/ipfs-cpinner-provider/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export type CID = string
66
export type Content = string
77

88
export type SavedContent = { id: CID, content: Content }
9+
export type Backup = { key: Key, id: CID }[]
910

1011
export interface MetadataManager {
1112
save(did: DID, key: Key, id: CID, contentSize: number): Promise<boolean>
@@ -14,6 +15,7 @@ export interface MetadataManager {
1415
getKeys (did: DID): Promise<Key[]>
1516
getUsedStorage (did: DID): Promise<number>
1617
getUsedStorageByDidKeyAndCid (did: DID, key: Key, cid: CID): Promise<number>
18+
getBackupByDid (did: DID): Promise<Backup>
1719
}
1820

1921
export interface IpfsClient {

modules/ipfs-cpinner-provider/test/ipfsPinnerProvider.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,15 @@ describe('ipfs pinner provider', function (this: {
224224

225225
expect(keys).toEqual([key, anotherKey])
226226
})
227+
228+
test('get backup with more than one key and content', async () => {
229+
const anotherKey = 'another key'
230+
231+
const id1 = await this.centralizedPinnerProvider.create(did, key, content)
232+
const id2 = await this.centralizedPinnerProvider.create(did, anotherKey, content)
233+
234+
const data = await this.centralizedPinnerProvider.getBackup(did)
235+
236+
expect(data).toEqual([{ key, id: id1 }, { key: anotherKey, id: id2 }])
237+
})
227238
})

modules/ipfs-cpinner-provider/test/metadataManager.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,25 @@ describe('metadata manager', function (this: {
170170
const totalUsedStorage = await this.metadataManager.getUsedStorage(did)
171171
expect(totalUsedStorage).toEqual(contentSize + anotherContentSize)
172172
})
173+
174+
test('should get empty array when getting a backup if no content created', async () => {
175+
const data = await this.metadataManager.getBackupByDid(did)
176+
177+
expect(data).toEqual([])
178+
})
179+
180+
test('should get an array containing created data when requesting the backup', async () => {
181+
await this.metadataManager.save(did, key, cid, contentSize)
182+
183+
const data = await this.metadataManager.getBackupByDid(did)
184+
expect(data).toEqual([{ key, id: cid }])
185+
})
186+
187+
test('should get an array with repeated data if it has been saved twice', async () => {
188+
await this.metadataManager.save(did, key, cid, contentSize)
189+
await this.metadataManager.save(did, key, cid, contentSize)
190+
191+
const data = await this.metadataManager.getBackupByDid(did)
192+
expect(data).toEqual([{ key, id: cid }, { key, id: cid }])
193+
})
173194
})

0 commit comments

Comments
 (0)