mirror of
https://github.com/aljazceru/gitpear.git
synced 2025-12-17 06:04:25 +01:00
Merge branch 'dzdidi:master' into master
This commit is contained in:
25
Readme.md
25
Readme.md
@@ -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`
|
||||||
|
|||||||
@@ -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)))
|
||||||
|
|||||||
14
src/rpc.js
14
src/rpc.js
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user