Merge branch 'dzdidi:master' into master

This commit is contained in:
2024-02-05 16:03:24 +00:00
committed by GitHub
3 changed files with 31 additions and 20 deletions

View File

@@ -45,12 +45,21 @@ All data will be persisted in application directory (default `~/.gitpear`). To c
### ACL (for authenticated access to enable support of PUSH) ### ACL (for authenticated access to enable support of PUSH)
Support of `push` capabilities only enabled for authenticated users. Currently supported authentication is based on [NIP98](https://github.com/nostr-protocol/nips/blob/master/98.md). Support of `push` capabilities only enabled for authenticated users. Currently supported authentications are based on:
To start daemon with authenticated support provide environment varibales `GIT_PEAR_AUTH` with value `nip98` and `GIT_PEAR_AUTH_NSEC` with value of your [NIP19 nsec](https://github.com/nostr-protocol/nips/blob/master/19.md). * [noise](https://github.com/libp2p/specs/blob/master/noise/README.md);
* [NIP98](https://github.com/nostr-protocol/nips/blob/master/98.md).
To start daemon with authenticated support provide environment varibales `GIT_PEAR_AUTH` with values `nip98` or `native`.
The `nip98` also requires `GIT_PEAR_AUTH_NSEC` with value of your [NIP19 nsec](https://github.com/nostr-protocol/nips/blob/master/19.md).
For example: For example:
``` ```
GIT_PEAR_AUTH=nip98 GIT_PEAR_AUTH_NSEC=nsec.... git pear daemon -s GIT_PEAR_AUTH=nip98 GIT_PEAR_AUTH_NSEC=nsec.... git pear daemon -s
``` ```
or
```
GIT_PEAR_AUTH=native git pear daemon -s
```
To manage access to repository use one or combination of the following commands, if `path` is not provide the command will be executed in the current directory. For `userId` use [NIP19 npub](https://github.com/nostr-protocol/nips/blob/master/19.md). To manage access to repository use one or combination of the following commands, if `path` is not provide the command will be executed in the current directory. For `userId` use [NIP19 npub](https://github.com/nostr-protocol/nips/blob/master/19.md).
@@ -120,18 +129,20 @@ git pull
Collaboration is possible with the following flow between Carol and David in a peer-to-peer manner. Collaboration is possible with the following flow between Carol and David in a peer-to-peer manner.
Supported authentication methods are `native` and `nip98`. The `nip98` authentication, requires environment variable `GIT_PEAR_AUTH_NSEC` with nsec
### Carol steps (as a server of code) ### Carol steps (as a server of code)
1. Start daemon 1. Start daemon
* `GIT_PEAR_AUTH_NSEC=<Carol's nsec> GIT_PEAR_AUTH='nip98' git pear daemon -s` * `GIT_PEAR_AUTH='native' git pear daemon -s`
2. Go to repository 2. Go to repository
* `cd repo` * `cd repo`
3. Initialize git pear repository 3. Initialize git pear repository
* `git pear init .` * `git pear init .`
4. Share repository wit hviben visibility () - (default is `public`) 4. Share repository wit hviben visibility () - (default is `public`)
* `git pear share . <private|public>` * `git pear share . public`
5. Add Daviv as a `contirbutor`. 5. Add Daviv as a `contirbutor`.
6. List David's npub as a contributor 6. List David's npub as a contributor
* `git pear acl add <David npub>:contributor` * `git pear acl add <David pub key hex>:contributor`
7. Retreive repo url and share it with Dave 7. Retreive repo url and share it with Dave
* `git pear list -s` * `git pear list -s`
@@ -139,14 +150,14 @@ Collaboration is possible with the following flow between Carol and David in a p
1. Start daemon. This will be needed later for push. Not that no auth or sec are provided which means that push to this place will not be supportedd. 1. Start daemon. This will be needed later for push. Not that no auth or sec are provided which means that push to this place will not be supportedd.
* `git pear daemon -s` * `git pear daemon -s`
2. Clone repository. Authorization data and type are necesary for server (Carol) to grant corresponding access persmissions 2. Clone repository. Authorization data and type are necesary for server (Carol) to grant corresponding access persmissions
* `GIT_PEAR_AUTH_NSEC=<David's nsec> GIT_PEAR_AUTH='nip98' git clone pear://<Carol's url>/<repo name>` * `GIT_PEAR_AUTH='native' git clone pear://<Carol's pub key hex>/<repo name>`
3. Do the necessary change in separate branch 3. Do the necessary change in separate branch
* `git checkout -b feat/david` * `git checkout -b feat/david`
* do change * do change
* `git add .` * `git add .`
* `git commit -s -m 'made by David'` * `git commit -s -m 'made by David'`
4. Push branch to origin 4. Push branch to origin
* `GIT_PEAR_AUTH_NSEC=<David's nsec> GIT_PEAR_AUTH='nip98' git push origin feat/david` * `GIT_PEAR_AUTH='native' git push origin feat/david`
### Carol steps ### Carol steps
1. For Carol the changes will arrive as branch `feat/david` into her `pear` 1. For Carol the changes will arrive as branch `feat/david` into her `pear`

View File

@@ -28,7 +28,7 @@ const targetKey = matches[1]
const repoName = matches[2] const repoName = matches[2]
const store = new Corestore(RAM) const store = new Corestore(RAM)
const swarm = new Hyperswarm({ keypair: home.getKeyPair() }) const swarm = new Hyperswarm({ keyPair: home.getKeyPair() })
if (!home.isDaemonRunning()) { if (!home.isDaemonRunning()) {
console.error('Please start git pear daemon') console.error('Please start git pear daemon')
@@ -42,7 +42,7 @@ swarm.on('connection', async (socket) => {
const rpc = new ProtomuxRPC(socket) const rpc = new ProtomuxRPC(socket)
let payload = { body: { url, method: 'get-repos' } } let payload = { body: { url, method: 'get-repos' } }
if (process.env.GIT_PEAR_AUTH) { if (process.env.GIT_PEAR_AUTH && process.env.GIT_PEAR_AUTH !== 'native') {
payload.header = await auth.getToken(payload.body) payload.header = await auth.getToken(payload.body)
} }
@@ -73,7 +73,7 @@ swarm.on('connection', async (socket) => {
await drive.core.update({ wait: true }) await drive.core.update({ wait: true })
payload = { body: { url, method: 'get-refs', data: repoName }} payload = { body: { url, method: 'get-refs', data: repoName }}
if (process.env.GIT_PEAR_AUTH) { if (process.env.GIT_PEAR_AUTH && process.env.GIT_PEAR_AUTH !== 'native') {
payload.header = await auth.getToken(payload.body) payload.header = await auth.getToken(payload.body)
} }
const refsRes = await rpc.request('get-refs', Buffer.from(JSON.stringify(payload))) const refsRes = await rpc.request('get-refs', Buffer.from(JSON.stringify(payload)))
@@ -101,10 +101,6 @@ async function talkToGit (refs, drive, repoName, rpc, commit) {
const isDelete = !src const isDelete = !src
const isForce = src.startsWith('+') const isForce = src.startsWith('+')
if (!home.isShared(repoName)) {
home.shareAppFolder(name)
}
dst = dst.replace('refs/heads/', '').replace('\n\n', '') dst = dst.replace('refs/heads/', '').replace('\n\n', '')
try { home.createAppFolder(repoName) } catch (e) { } try { home.createAppFolder(repoName) } catch (e) { }
@@ -134,7 +130,7 @@ async function talkToGit (refs, drive, repoName, rpc, commit) {
data: `${dst}#${commit}`, data: `${dst}#${commit}`,
method method
} } } }
if (process.env.GIT_PEAR_AUTH) { if (process.env.GIT_PEAR_AUTH && process.env.GIT_PEAR_AUTH !== 'native') {
payload.header = await auth.getToken(payload.body) payload.header = await auth.getToken(payload.body)
} }
const res = await rpc.request(method, Buffer.from(JSON.stringify(payload))) const res = await rpc.request(method, Buffer.from(JSON.stringify(payload)))

View File

@@ -1,4 +1,5 @@
const ProtomuxRPC = require('protomux-rpc') const ProtomuxRPC = require('protomux-rpc')
const SecretStream = require('@hyperswarm/secret-stream')
const { spawn } = require('child_process') const { spawn } = require('child_process')
const home = require('./home') const home = require('./home')
const auth = require('./auth') const auth = require('./auth')
@@ -16,19 +17,21 @@ module.exports = class RPC {
if (this.connections[peerInfo.publicKey]) return this.connections[peerInfo.publicKey] if (this.connections[peerInfo.publicKey]) return this.connections[peerInfo.publicKey]
const rpc = new ProtomuxRPC(socket) const rpc = new ProtomuxRPC(socket)
rpc.on('error', err => console.error('rpc error', err))
rpc.on('close', () => delete this.connections[peerInfo.publicKey])
// XXX: handshaking can be used for access and permission management // XXX: handshaking can be used for access and permission management
// for example check of peerInfo.publicKey is in a list of allowed keys // for example check of peerInfo.publicKey is in a list of allowed keys
// which can in turn be stored in a .git-daemon-export-ok file // which can in turn be stored in a .git-daemon-export-ok file
/* -- PULL HANDLERS -- */ /* -- PULL HANDLERS -- */
rpc.respond('get-repos', async req => await this.getReposHandler(peerInfo.publicKey, req)) rpc.respond('get-repos', async req => await this.getReposHandler(socket.remotePublicKey, req))
rpc.respond('get-refs', async req => await this.getRefsHandler(peerInfo.publicKey, req)) rpc.respond('get-refs', async req => await this.getRefsHandler(socket.remotePublicKey, req))
if (process.env.GIT_PEAR_AUTH) { if (process.env.GIT_PEAR_AUTH) {
/* -- PUSH HANDLERS -- */ /* -- PUSH HANDLERS -- */
rpc.respond('push', async req => await this.pushHandler(peerInfo.publicKey, req)) rpc.respond('push', async req => await this.pushHandler(socket.remotePublicKey, req))
rpc.respond('f-push', async req => await this.forcePushHandler(peerInfo.publicKey, req)) rpc.respond('f-push', async req => await this.forcePushHandler(socket.remotePublicKey, req))
rpc.respond('d-branch', async req => await this.deleteBranchHandler(peerInfo.publicKey, req)) rpc.respond('d-branch', async req => await this.deleteBranchHandler(socket.remotePublicKey, req))
} }
this.connections[peerInfo.publicKey] = rpc this.connections[peerInfo.publicKey] = rpc
@@ -150,6 +153,7 @@ module.exports = class RPC {
async authenticate (publicKey, request) { async authenticate (publicKey, request) {
if (!process.env.GIT_PEAR_AUTH) return publicKey.toString('hex') if (!process.env.GIT_PEAR_AUTH) return publicKey.toString('hex')
if (process.env.GIT_PEAR_AUTH === 'native') return publicKey.toString('hex')
if (!request.header) throw new Error('You are not allowed to access this repo') if (!request.header) throw new Error('You are not allowed to access this repo')
return (await auth.getId({ ...request.body, payload: request.header })).userId return (await auth.getId({ ...request.body, payload: request.header })).userId