mirror of
https://github.com/aljazceru/gitpear.git
synced 2025-12-17 06:04:25 +01:00
cli: path as option; lint; quit option
Signed-off-by: dzdidi <deniszalessky@gmail.com>
This commit is contained in:
14
src/acl.js
14
src/acl.js
@@ -3,20 +3,20 @@ const fs = require('fs')
|
|||||||
|
|
||||||
const ROLES = {
|
const ROLES = {
|
||||||
owner: {
|
owner: {
|
||||||
description: 'Read and write to all branches, and ACL management',
|
description: 'Read and write to all branches, and ACL management'
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
description: 'Read and write to all branches',
|
description: 'Read and write to all branches'
|
||||||
},
|
},
|
||||||
contributor: {
|
contributor: {
|
||||||
description: 'Read and write to all branches except protected ones',
|
description: 'Read and write to all branches except protected ones'
|
||||||
},
|
},
|
||||||
viewer: {
|
viewer: {
|
||||||
description: 'Read all branches',
|
description: 'Read all branches'
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
const DEFAULT_ACL = {
|
const DEFAULT_ACL = {
|
||||||
visibility: 'public', // public|private
|
visibility: 'public', // public|private
|
||||||
protectedBranches: ['master', 'main'],
|
protectedBranches: ['master', 'main'],
|
||||||
ACL: {}
|
ACL: {}
|
||||||
}
|
}
|
||||||
@@ -127,5 +127,5 @@ module.exports = {
|
|||||||
getAdmins,
|
getAdmins,
|
||||||
getContributors,
|
getContributors,
|
||||||
getViewers,
|
getViewers,
|
||||||
revokeAccessFromUser,
|
revokeAccessFromUser
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
function getId(data) {
|
function getId (data) {
|
||||||
if (!process.env.GIT_PEAR_AUTH) return payload
|
if (!process.env.GIT_PEAR_AUTH) return data
|
||||||
if (process.env.GIT_PEAR_AUTH === 'nip98') {
|
if (process.env.GIT_PEAR_AUTH === 'nip98') {
|
||||||
const nip98 = require('./nip98')
|
const nip98 = require('./nip98')
|
||||||
return nip98.getId(data)
|
return nip98.getId(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getToken(payload) {
|
async function getToken (payload) {
|
||||||
if (!process.env.GIT_PEAR_AUTH) return userId
|
if (!process.env.GIT_PEAR_AUTH) return payload
|
||||||
if (process.env.GIT_PEAR_AUTH === 'nip98') {
|
if (process.env.GIT_PEAR_AUTH === 'nip98') {
|
||||||
const nip98 = require('./nip98')
|
const nip98 = require('./nip98')
|
||||||
return nip98.getToken(payload)
|
return nip98.getToken(payload)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const { nip98, nip19, finalizeEvent } = require('nostr-tools')
|
const { nip98, nip19, finalizeEvent } = require('nostr-tools')
|
||||||
|
|
||||||
async function getToken({ url, method, data }) {
|
async function getToken ({ url, method, data }) {
|
||||||
if (!process.env.GIT_PEAR_AUTH_NSEC) throw new Error('Missing NSEC')
|
if (!process.env.GIT_PEAR_AUTH_NSEC) throw new Error('Missing NSEC')
|
||||||
const { data: sK } = nip19.decode(process.env.GIT_PEAR_AUTH_NSEC)
|
const { data: sK } = nip19.decode(process.env.GIT_PEAR_AUTH_NSEC)
|
||||||
return nip98.getToken(
|
return nip98.getToken(
|
||||||
@@ -13,11 +13,11 @@ async function getToken({ url, method, data }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
async function getId({ payload, url, method, data }) {
|
async function getId ({ payload, url, method, data }) {
|
||||||
const event = JSON.parse(Buffer.from(payload, 'base64').toString())
|
const event = JSON.parse(Buffer.from(payload, 'base64').toString())
|
||||||
const isValid = await nip98.validateEvent(event, url, method, data)
|
const isValid = await nip98.validateEvent(event, url, method, data)
|
||||||
if (!isValid) throw new Error('Invalid event')
|
if (!isValid) throw new Error('Invalid event')
|
||||||
return {
|
return {
|
||||||
...event,
|
...event,
|
||||||
userId: nip19.npubEncode(event.pubkey)
|
userId: nip19.npubEncode(event.pubkey)
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/cli.js
26
src/cli.js
@@ -6,7 +6,6 @@ const commander = require('commander')
|
|||||||
const program = new commander.Command()
|
const program = new commander.Command()
|
||||||
|
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
|
||||||
|
|
||||||
const home = require('./home')
|
const home = require('./home')
|
||||||
const acl = require('./acl')
|
const acl = require('./acl')
|
||||||
@@ -25,10 +24,9 @@ program
|
|||||||
program
|
program
|
||||||
.command('init')
|
.command('init')
|
||||||
.description('initialize a gitpear repo')
|
.description('initialize a gitpear repo')
|
||||||
.option('-p, --path [path]', 'paht to the git repo', '.')
|
|
||||||
.option('-s, --share [branch]', 'share the repo as public, default false, default branch is current', '')
|
.option('-s, --share [branch]', 'share the repo as public, default false, default branch is current', '')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const fullPath = path.resolve(options.path)
|
const fullPath = path.resolve('.')
|
||||||
checkIfGitRepo(fullPath)
|
checkIfGitRepo(fullPath)
|
||||||
|
|
||||||
const name = fullPath.split(path.sep).pop()
|
const name = fullPath.split(path.sep).pop()
|
||||||
@@ -42,7 +40,7 @@ program
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
home.createAppFolder(name)
|
home.createAppFolder(name)
|
||||||
console.log(`Added project "${name}" to gitpear`)
|
console.log(`Added project "${name}" to gitpear`)
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
try {
|
try {
|
||||||
@@ -67,9 +65,8 @@ program
|
|||||||
.description('share a gitpear repo')
|
.description('share a gitpear repo')
|
||||||
.option('-b, --branch [b]', 'branch to share, default is current branch', '')
|
.option('-b, --branch [b]', 'branch to share, default is current branch', '')
|
||||||
.option('-v, --visibility [v]', 'visibility of the repo', 'public')
|
.option('-v, --visibility [v]', 'visibility of the repo', 'public')
|
||||||
.option('-p, --path [path]', 'path to the repo', '.')
|
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const fullPath = path.resolve(options.path)
|
const fullPath = path.resolve('.')
|
||||||
checkIfGitRepo(fullPath)
|
checkIfGitRepo(fullPath)
|
||||||
|
|
||||||
const name = fullPath.split(path.sep).pop()
|
const name = fullPath.split(path.sep).pop()
|
||||||
@@ -115,7 +112,6 @@ program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('unshare')
|
.command('unshare')
|
||||||
@@ -184,7 +180,7 @@ program
|
|||||||
opts.stdio = 'inherit'
|
opts.stdio = 'inherit'
|
||||||
} else {
|
} else {
|
||||||
opts.detached = true
|
opts.detached = true
|
||||||
opts.stdio = [ 'ignore', home.getOutStream(), home.getErrStream() ]
|
opts.stdio = ['ignore', home.getOutStream(), home.getErrStream()]
|
||||||
}
|
}
|
||||||
|
|
||||||
const daemon = spawn('git-peard', opts)
|
const daemon = spawn('git-peard', opts)
|
||||||
@@ -211,7 +207,7 @@ program
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function localBranchProtectionRules(a, b, p, options) {
|
function localBranchProtectionRules (a, b, p, options) {
|
||||||
const fullPath = path.resolve(p)
|
const fullPath = path.resolve(p)
|
||||||
checkIfGitRepo(fullPath)
|
checkIfGitRepo(fullPath)
|
||||||
|
|
||||||
@@ -238,8 +234,7 @@ function localBranchProtectionRules(a, b, p, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function localACL(a, u, p, options) {
|
function localACL (a, u, p, options) {
|
||||||
console.log('localACL', { a, u, p, options })
|
|
||||||
const fullPath = path.resolve(p)
|
const fullPath = path.resolve(p)
|
||||||
checkIfGitRepo(fullPath)
|
checkIfGitRepo(fullPath)
|
||||||
|
|
||||||
@@ -266,7 +261,7 @@ function localACL(a, u, p, options) {
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [ userId, role ] = u.split(':')
|
const [userId, role] = u.split(':')
|
||||||
if (repoACL.ACL[userId]) {
|
if (repoACL.ACL[userId]) {
|
||||||
console.error(`${userId} already has access to ${name} as ${repoACL.ACL[userId]}`)
|
console.error(`${userId} already has access to ${name} as ${repoACL.ACL[userId]}`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
@@ -290,11 +285,10 @@ function localACL(a, u, p, options) {
|
|||||||
|
|
||||||
acl.revokeAccessFromUser(name, u)
|
acl.revokeAccessFromUser(name, u)
|
||||||
console.log(`Removed ${u} from ${name}`)
|
console.log(`Removed ${u} from ${name}`)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remoteBranchProtectionRules(a, b, p, options) {
|
async function remoteBranchProtectionRules (a, b, p, options) {
|
||||||
if (a === 'list') {
|
if (a === 'list') {
|
||||||
await aclRemote.list(p, b, { branch: true })
|
await aclRemote.list(p, b, { branch: true })
|
||||||
} else if (a === 'add') {
|
} else if (a === 'add') {
|
||||||
@@ -314,7 +308,7 @@ async function remoteBranchProtectionRules(a, b, p, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remoteACL(a, b, p, options) {
|
async function remoteACL (a, b, p, options) {
|
||||||
if (a === 'list') {
|
if (a === 'list') {
|
||||||
await aclRemote.list(p, b)
|
await aclRemote.list(p, b)
|
||||||
} else if (a === 'add') {
|
} else if (a === 'add') {
|
||||||
@@ -338,7 +332,7 @@ async function remoteACL(a, b, p, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function share(name, branchToShare, options) {
|
async function share (name, branchToShare, options) {
|
||||||
let aclOptions
|
let aclOptions
|
||||||
let message = `Shared "${name}" project, ${branchToShare} branch`
|
let message = `Shared "${name}" project, ${branchToShare} branch`
|
||||||
if (options?.visibility) {
|
if (options?.visibility) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const { spawn } = require('child_process')
|
|
||||||
const ProtomuxRPC = require('protomux-rpc')
|
const ProtomuxRPC = require('protomux-rpc')
|
||||||
|
|
||||||
const RAM = require('random-access-memory')
|
const RAM = require('random-access-memory')
|
||||||
@@ -14,8 +13,6 @@ const home = require('./home')
|
|||||||
const auth = require('./auth')
|
const auth = require('./auth')
|
||||||
const acl = require('./acl')
|
const acl = require('./acl')
|
||||||
|
|
||||||
const fs = require('fs')
|
|
||||||
|
|
||||||
const url = process.argv[3]
|
const url = process.argv[3]
|
||||||
const matches = url.match(/pear:\/\/([a-f0-9]{64})\/(.*)/)
|
const matches = url.match(/pear:\/\/([a-f0-9]{64})\/(.*)/)
|
||||||
|
|
||||||
@@ -76,13 +73,13 @@ 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 && process.env.GIT_PEAR_AUTH !== 'native') {
|
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)))
|
||||||
|
|
||||||
let commit
|
let commit
|
||||||
try {
|
try {
|
||||||
commit = await git.getCommit()
|
commit = await git.getCommit()
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
@@ -99,7 +96,7 @@ async function talkToGit (refs, drive, repoName, rpc, commit) {
|
|||||||
process.stdout.write('push\n')
|
process.stdout.write('push\n')
|
||||||
process.stdout.write('fetch\n\n')
|
process.stdout.write('fetch\n\n')
|
||||||
} else if (chunk && chunk.search(/^push/) !== -1) {
|
} else if (chunk && chunk.search(/^push/) !== -1) {
|
||||||
const [_command, path] = chunk.split(' ')
|
const path = chunk.split(' ')[1]
|
||||||
let [src, dst] = path.split(':')
|
let [src, dst] = path.split(':')
|
||||||
|
|
||||||
const isDelete = !src
|
const isDelete = !src
|
||||||
@@ -107,13 +104,6 @@ async function talkToGit (refs, drive, repoName, rpc, commit) {
|
|||||||
|
|
||||||
dst = dst.replace('refs/heads/', '').replace('\n\n', '')
|
dst = dst.replace('refs/heads/', '').replace('\n\n', '')
|
||||||
|
|
||||||
try { home.createAppFolder(repoName) } catch (e) { }
|
|
||||||
try { await git.createBareRepo(repoName) } catch (e) { }
|
|
||||||
try { await git.addRemote(repoName) } catch (e) { }
|
|
||||||
try { await git.push(dst) } catch (e) { }
|
|
||||||
try { home.shareAppFolder(repoName) } catch (e) { }
|
|
||||||
try { acl.setACL(repoName, acl.getACL(repoName)) } catch (e) { }
|
|
||||||
|
|
||||||
let method
|
let method
|
||||||
if (isDelete) {
|
if (isDelete) {
|
||||||
method = 'd-branch'
|
method = 'd-branch'
|
||||||
@@ -128,16 +118,25 @@ async function talkToGit (refs, drive, repoName, rpc, commit) {
|
|||||||
method = 'push'
|
method = 'push'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try { home.createAppFolder(repoName) } catch (e) { }
|
||||||
|
try { await git.createBareRepo(repoName) } catch (e) { }
|
||||||
|
try { await git.addRemote(repoName, { quite: true }) } catch (e) { }
|
||||||
|
try { await git.push(dst, isForce) } catch (e) { }
|
||||||
|
try { home.shareAppFolder(repoName) } catch (e) { }
|
||||||
|
try { acl.setACL(repoName, acl.getACL(repoName)) } catch (e) { }
|
||||||
|
|
||||||
const publicKey = home.readPk()
|
const publicKey = home.readPk()
|
||||||
let payload = { body: {
|
const payload = {
|
||||||
url: `pear://${publicKey}/${repoName}`,
|
body: {
|
||||||
data: `${dst}#${commit}`,
|
url: `pear://${publicKey}/${repoName}`,
|
||||||
method
|
data: `${dst}#${commit}`,
|
||||||
} }
|
method
|
||||||
|
}
|
||||||
|
}
|
||||||
if (process.env.GIT_PEAR_AUTH && process.env.GIT_PEAR_AUTH !== 'native') {
|
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)))
|
await rpc.request(method, Buffer.from(JSON.stringify(payload)))
|
||||||
|
|
||||||
process.stdout.write('\n\n')
|
process.stdout.write('\n\n')
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
|
|||||||
10
src/git.js
10
src/git.js
@@ -64,9 +64,9 @@ async function createBareRepo (name) {
|
|||||||
return await doGit(init)
|
return await doGit(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addRemote (name) {
|
async function addRemote (name, opts = { quiet: false }) {
|
||||||
const init = spawn('git', ['remote', 'add', 'pear', getCodePath(name)])
|
const init = spawn('git', ['remote', 'add', 'pear', getCodePath(name)])
|
||||||
return await doGit(init)
|
return await doGit(init, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function push (branch = 'master', force = false) {
|
async function push (branch = 'master', force = false) {
|
||||||
@@ -76,8 +76,8 @@ async function push (branch = 'master', force = false) {
|
|||||||
return await doGit(push)
|
return await doGit(push)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doGit (child) {
|
async function doGit (child, opts = { quiet: false }) {
|
||||||
child.stderr.pipe(process.stderr)
|
if (!opts.quiet) child.stderr.pipe(process.stderr)
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
child.on('close', (code) => {
|
child.on('close', (code) => {
|
||||||
if (code) {
|
if (code) {
|
||||||
@@ -229,5 +229,5 @@ module.exports = {
|
|||||||
addRemote,
|
addRemote,
|
||||||
push,
|
push,
|
||||||
getCommit,
|
getCommit,
|
||||||
getCurrentBranch,
|
getCurrentBranch
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ const ACL = require('../acl')
|
|||||||
const home = require('../home')
|
const home = require('../home')
|
||||||
|
|
||||||
async function getACLHandler (publicKey, req) {
|
async function getACLHandler (publicKey, req) {
|
||||||
const { repoName, userId, acl } = await parseACLRequest.bind(this)(publicKey, req)
|
const { repoName } = await parseACLRequest.bind(this)(publicKey, req)
|
||||||
const repoACL = ACL.getACL(repoName)
|
const repoACL = ACL.getACL(repoName)
|
||||||
|
|
||||||
return Buffer.from(JSON.stringify(repoACL))
|
return Buffer.from(JSON.stringify(repoACL))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addACLHandler (publicKey, req) {
|
async function addACLHandler (publicKey, req) {
|
||||||
const { repoName, userId, acl, isBranch, name } = await parseACLRequest.bind(this)(publicKey, req)
|
const { repoName, isBranch, name } = await parseACLRequest.bind(this)(publicKey, req)
|
||||||
|
|
||||||
isBranch ? ACL.addProtectedBranch(repoName, name) : ACL.grantAccessToUser(repoName, ...name.split(':'))
|
isBranch ? ACL.addProtectedBranch(repoName, name) : ACL.grantAccessToUser(repoName, ...name.split(':'))
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ async function addACLHandler (publicKey, req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function delACLHandler (publicKey, req) {
|
async function delACLHandler (publicKey, req) {
|
||||||
const { repoName, userId, acl, isBranch, name } = await parseACLRequest.bind(this)(publicKey, req)
|
const { repoName, isBranch, name } = await parseACLRequest.bind(this)(publicKey, req)
|
||||||
|
|
||||||
isBranch ? ACL.removeProtectedBranch(repoName, name) : ACL.revokeAccessFromUser(repoName, name)
|
isBranch ? ACL.removeProtectedBranch(repoName, name) : ACL.revokeAccessFromUser(repoName, name)
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ async function delACLHandler (publicKey, req) {
|
|||||||
return Buffer.from(JSON.stringify(repoACL))
|
return Buffer.from(JSON.stringify(repoACL))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parseACLRequest(publicKey, req) {
|
async function parseACLRequest (publicKey, req) {
|
||||||
if (!req) throw new Error('Request is empty')
|
if (!req) throw new Error('Request is empty')
|
||||||
const request = JSON.parse(req.toString())
|
const request = JSON.parse(req.toString())
|
||||||
const userId = await this.authenticate(publicKey, request)
|
const userId = await this.authenticate(publicKey, request)
|
||||||
@@ -42,12 +42,12 @@ async function parseACLRequest(publicKey, req) {
|
|||||||
name: request.body.name,
|
name: request.body.name,
|
||||||
userId,
|
userId,
|
||||||
acl: request.body.acl,
|
acl: request.body.acl,
|
||||||
isBranch: !!request.body.branch,
|
isBranch: !!request.body.branch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getACLHandler,
|
getACLHandler,
|
||||||
addACLHandler,
|
addACLHandler,
|
||||||
delACLHandler,
|
delACLHandler
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ const home = require('../home')
|
|||||||
const { spawn } = require('child_process')
|
const { spawn } = require('child_process')
|
||||||
|
|
||||||
async function getReposHandler (publicKey, req) {
|
async function getReposHandler (publicKey, req) {
|
||||||
const { branch, url, userId } = await parseReq.bind(this)(publicKey, req)
|
const { userId } = await parseReq.bind(this)(publicKey, req)
|
||||||
|
|
||||||
const res = {}
|
const res = {}
|
||||||
for (const repoName in this.repositories) {
|
for (const repoName in this.repositories) {
|
||||||
// TODO: add only public repos and those which are shared with the peer
|
|
||||||
// Alternatively return only requested repo
|
|
||||||
const isPublic = (ACL.getACL(repoName).visibility === 'public')
|
const isPublic = (ACL.getACL(repoName).visibility === 'public')
|
||||||
if (isPublic || ACL.getViewers(repoName).includes(userId)) {
|
if (isPublic || ACL.getViewers(repoName).includes(userId)) {
|
||||||
res[repoName] = this.drives[repoName].key.toString('hex')
|
res[repoName] = this.drives[repoName].key.toString('hex')
|
||||||
@@ -18,7 +16,7 @@ async function getReposHandler (publicKey, req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getRefsHandler (publicKey, req) {
|
async function getRefsHandler (publicKey, req) {
|
||||||
const { repoName, branch, url, userId } = await parseReq.bind(this)(publicKey, req)
|
const { repoName, userId } = await parseReq.bind(this)(publicKey, req)
|
||||||
const res = this.repositories[repoName]
|
const res = this.repositories[repoName]
|
||||||
|
|
||||||
const isPublic = (ACL.getACL(repoName).visibility === 'public')
|
const isPublic = (ACL.getACL(repoName).visibility === 'public')
|
||||||
@@ -43,14 +41,7 @@ async function pushHandler (publicKey, req) {
|
|||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const env = { ...process.env, GIT_DIR: home.getCodePath(repoName) }
|
const env = { ...process.env, GIT_DIR: home.getCodePath(repoName) }
|
||||||
const child = spawn('git', ['fetch', url, `${branch}:${branch}`], { env })
|
const child = spawn('git', ['fetch', url, `${branch}:${branch}`], { env })
|
||||||
let errBuffer = Buffer.from('')
|
return doGit(child, resolve, reject)
|
||||||
child.stderr.on('data', data => {
|
|
||||||
errBuffer = Buffer.concat([errBuffer, data])
|
|
||||||
})
|
|
||||||
|
|
||||||
child.on('close', code => {
|
|
||||||
return code === 0 ? resolve(errBuffer) : reject(errBuffer)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,19 +59,12 @@ async function forcePushHandler (publicKey, req) {
|
|||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const env = { ...process.env, GIT_DIR: home.getCodePath(repoName) }
|
const env = { ...process.env, GIT_DIR: home.getCodePath(repoName) }
|
||||||
const child = spawn('git', ['fetch', url, `${branch}:${branch}`, '--force'], { env })
|
const child = spawn('git', ['fetch', url, `${branch}:${branch}`, '--force'], { env })
|
||||||
let errBuffer = Buffer.from('')
|
return doGit(child, resolve, reject)
|
||||||
child.stderr.on('data', data => {
|
|
||||||
errBuffer = Buffer.concat([errBuffer, data])
|
|
||||||
})
|
|
||||||
|
|
||||||
child.on('close', code => {
|
|
||||||
return code === 0 ? resolve(errBuffer) : reject(errBuffer)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteBranchHandler (publicKey, req) {
|
async function deleteBranchHandler (publicKey, req) {
|
||||||
const { url, repoName, branch, userId } = await parseReq.bind(this)(publicKey, req)
|
const { repoName, branch, userId } = await parseReq.bind(this)(publicKey, req)
|
||||||
const isContributor = ACL.getContributors(repoName).includes(userId)
|
const isContributor = ACL.getContributors(repoName).includes(userId)
|
||||||
|
|
||||||
if (!isContributor) throw new Error('You are not allowed to push to this repo')
|
if (!isContributor) throw new Error('You are not allowed to push to this repo')
|
||||||
@@ -93,34 +77,46 @@ async function deleteBranchHandler (publicKey, req) {
|
|||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const env = { ...process.env, GIT_DIR: home.getCodePath(repoName) }
|
const env = { ...process.env, GIT_DIR: home.getCodePath(repoName) }
|
||||||
const child = spawn('git', ['branch', '-D', branch], { env })
|
const child = spawn('git', ['branch', '-D', branch], { env })
|
||||||
let errBuffer = Buffer.from('')
|
return doGit(child, resolve, reject)
|
||||||
child.stderr.on('data', data => {
|
|
||||||
errBuffer = Buffer.concat([errBuffer, data])
|
|
||||||
})
|
|
||||||
|
|
||||||
child.on('close', code => {
|
|
||||||
return code === 0 ? resolve(errBuffer) : reject(errBuffer)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parseReq(publicKey, req) {
|
async function parseReq (publicKey, req) {
|
||||||
if (!req) throw new Error('Request is empty')
|
if (!req) throw new Error('Request is empty')
|
||||||
const request = JSON.parse(req.toString())
|
const request = JSON.parse(req.toString())
|
||||||
const parsed = {
|
const parsed = {
|
||||||
repoName: request.body.url?.split('/')?.pop(),
|
repoName: request.body.url?.split('/')?.pop(),
|
||||||
branch: request.body.data?.split('#')[0],
|
branch: request.body.data?.split('#')[0],
|
||||||
url: request.body.url,
|
url: request.body.url,
|
||||||
userId: await this.authenticate(publicKey, request),
|
userId: await this.authenticate(publicKey, request)
|
||||||
}
|
}
|
||||||
return parsed
|
return parsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doGit (child, resolve, reject) {
|
||||||
|
let errBuffer = Buffer.from('')
|
||||||
|
let outBuffer = Buffer.from('')
|
||||||
|
|
||||||
|
child.stdout.on('data', data => {
|
||||||
|
outBuffer = Buffer.concat([outBuffer, data])
|
||||||
|
})
|
||||||
|
|
||||||
|
child.stderr.on('data', data => {
|
||||||
|
errBuffer = Buffer.concat([errBuffer, data])
|
||||||
|
})
|
||||||
|
|
||||||
|
child.on('close', code => {
|
||||||
|
console.error('errBuffer', errBuffer.toString())
|
||||||
|
console.log('outBuffer', outBuffer.toString())
|
||||||
|
|
||||||
|
return code === 0 ? resolve(outBuffer) : reject(errBuffer)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getReposHandler,
|
getReposHandler,
|
||||||
getRefsHandler,
|
getRefsHandler,
|
||||||
pushHandler,
|
pushHandler,
|
||||||
forcePushHandler,
|
forcePushHandler,
|
||||||
deleteBranchHandler,
|
deleteBranchHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ const acl = require('./acl')
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
git,
|
git,
|
||||||
acl,
|
acl
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const auth = require('../auth')
|
|||||||
|
|
||||||
const { printACL, printACLForUser, logBranches } = require('../utils')
|
const { printACL, printACLForUser, logBranches } = require('../utils')
|
||||||
|
|
||||||
async function list(url, name, rpc, opts) {
|
async function list (url, name, rpc, opts) {
|
||||||
const payload = { body: { url, method: 'get-acl' } }
|
const payload = { body: { url, method: 'get-acl' } }
|
||||||
if (process.env.GIT_PEAR_AUTH && process.env.GIT_PEAR_AUTH !== 'native') {
|
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)
|
||||||
@@ -20,15 +20,15 @@ async function list(url, name, rpc, opts) {
|
|||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function listACLUser(repoACL, u) {
|
function listACLUser (repoACL, u) {
|
||||||
u ? printACLForUser(repoACL, u) : printACL(repoACL)
|
u ? printACLForUser(repoACL, u) : printACL(repoACL)
|
||||||
}
|
}
|
||||||
|
|
||||||
function listACLBranch(repoACL) {
|
function listACLBranch (repoACL) {
|
||||||
logBranches(repoACL)
|
logBranches(repoACL)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function add(url, name, rpc, opts) {
|
async function add (url, name, rpc, opts) {
|
||||||
const payload = { body: { url, method: 'add-acl', name } }
|
const payload = { body: { url, method: 'add-acl', name } }
|
||||||
if (opts.branch) payload.body.branch = true
|
if (opts.branch) payload.body.branch = true
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ async function add(url, name, rpc, opts) {
|
|||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function del(url, name, rpc, opts) {
|
async function del (url, name, rpc, opts) {
|
||||||
const payload = { body: { url, method: 'del-acl', name } }
|
const payload = { body: { url, method: 'del-acl', name } }
|
||||||
if (opts.branch) payload.body.branch = true
|
if (opts.branch) payload.body.branch = true
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ async function wrapper (url, name, opts = {}, cb) {
|
|||||||
swarm.on('connection', async (socket) => {
|
swarm.on('connection', async (socket) => {
|
||||||
const rpc = new ProtomuxRPC(socket)
|
const rpc = new ProtomuxRPC(socket)
|
||||||
|
|
||||||
let payload = { body: { url, method: 'get-repos' } }
|
const payload = { body: { url, method: 'get-repos' } }
|
||||||
if (!process.env.GIT_PEAR_AUTH) {
|
if (!process.env.GIT_PEAR_AUTH) {
|
||||||
console.debug('Retreiving data using un-authenticated access')
|
console.debug('Retreiving data using un-authenticated access')
|
||||||
} else {
|
} else {
|
||||||
@@ -112,5 +112,5 @@ async function wrapper (url, name, opts = {}, cb) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
list: (url, name, opts) => wrapper(url, name, opts, list),
|
list: (url, name, opts) => wrapper(url, name, opts, list),
|
||||||
add: (url, name, opts) => wrapper(url, name, opts, add),
|
add: (url, name, opts) => wrapper(url, name, opts, add),
|
||||||
remove: (url, name, opts) => wrapper(url, name, opts, del),
|
remove: (url, name, opts) => wrapper(url, name, opts, del)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ const aclRemote = require('./acl-remote')
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
listRemote,
|
listRemote,
|
||||||
aclRemote,
|
aclRemote
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ module.exports = async function listRemote (url) {
|
|||||||
swarm.on('connection', async (socket) => {
|
swarm.on('connection', async (socket) => {
|
||||||
const rpc = new ProtomuxRPC(socket)
|
const rpc = new ProtomuxRPC(socket)
|
||||||
|
|
||||||
let payload = { body: { url, method: 'get-repos' } }
|
const payload = { body: { url, method: 'get-repos' } }
|
||||||
if (!process.env.GIT_PEAR_AUTH) {
|
if (!process.env.GIT_PEAR_AUTH) {
|
||||||
console.debug('Retreiving data using un-authenticated access')
|
console.debug('Retreiving data using un-authenticated access')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
const ProtomuxRPC = require('protomux-rpc')
|
const ProtomuxRPC = require('protomux-rpc')
|
||||||
const SecretStream = require('@hyperswarm/secret-stream')
|
|
||||||
const { spawn } = require('child_process')
|
|
||||||
const home = require('./home')
|
|
||||||
const auth = require('./auth')
|
const auth = require('./auth')
|
||||||
const { git, acl } = require('./rpc-handlers')
|
const { git, acl } = require('./rpc-handlers')
|
||||||
|
|
||||||
@@ -26,13 +23,13 @@ module.exports = class RPC {
|
|||||||
|
|
||||||
/* -- PULL HANDLERS -- */
|
/* -- PULL HANDLERS -- */
|
||||||
rpc.respond('get-repos', async req => await git.getReposHandler.bind(this)(socket.remotePublicKey, req))
|
rpc.respond('get-repos', async req => await git.getReposHandler.bind(this)(socket.remotePublicKey, req))
|
||||||
rpc.respond('get-refs', async req => await git.getRefsHandler.bind(this)(socket.remotePublicKey, req))
|
rpc.respond('get-refs', async req => await git.getRefsHandler.bind(this)(socket.remotePublicKey, req))
|
||||||
|
|
||||||
if (!process.env.GIT_PEAR_AUTH) return
|
if (!process.env.GIT_PEAR_AUTH) return
|
||||||
|
|
||||||
/* -- PUSH HANDLERS -- */
|
/* -- PUSH HANDLERS -- */
|
||||||
rpc.respond('push', async req => await git.pushHandler.bind(this)(socket.remotePublicKey, req))
|
rpc.respond('push', async req => await git.pushHandler.bind(this)(socket.remotePublicKey, req))
|
||||||
rpc.respond('f-push', async req => await git.forcePushHandler.bind(this)(socket.remotePublicKey, req))
|
rpc.respond('f-push', async req => await git.forcePushHandler.bind(this)(socket.remotePublicKey, req))
|
||||||
rpc.respond('d-branch', async req => await git.deleteBranchHandler.bind(this)(socket.remotePublicKey, req))
|
rpc.respond('d-branch', async req => await git.deleteBranchHandler.bind(this)(socket.remotePublicKey, req))
|
||||||
|
|
||||||
/* -- REPO ADMINISTRATION HANDLERS -- */
|
/* -- REPO ADMINISTRATION HANDLERS -- */
|
||||||
|
|||||||
16
src/utils.js
16
src/utils.js
@@ -1,7 +1,7 @@
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
function printACL(repoACL) {
|
function printACL (repoACL) {
|
||||||
console.log('Repo Visibility:', '\t', repoACL.visibility)
|
console.log('Repo Visibility:', '\t', repoACL.visibility)
|
||||||
console.log('Protected Branch(s):', '\t', repoACL.protectedBranches.join(', '))
|
console.log('Protected Branch(s):', '\t', repoACL.protectedBranches.join(', '))
|
||||||
console.log('User:', '\t', 'Role:')
|
console.log('User:', '\t', 'Role:')
|
||||||
@@ -10,20 +10,20 @@ function printACL(repoACL) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function printACLForUser(repoACL, u) {
|
function printACLForUser (repoACL, u) {
|
||||||
console.log('Repo Visibility:', '\t', repoACL.visibility)
|
console.log('Repo Visibility:', '\t', repoACL.visibility)
|
||||||
console.log('Protected Branch(s):', '\t', repoACL.protectedBranches.join(', '))
|
console.log('Protected Branch(s):', '\t', repoACL.protectedBranches.join(', '))
|
||||||
console.log('User:', u, '\t', repoACL.ACL[u])
|
console.log('User:', u, '\t', repoACL.ACL[u])
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIfGitRepo(p) {
|
function checkIfGitRepo (p) {
|
||||||
if (!fs.existsSync(path.join(p, '.git'))) {
|
if (!fs.existsSync(path.join(p, '.git'))) {
|
||||||
console.error(` ${p} is not a git repo`)
|
console.error(` ${p} is not a git repo`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function logBranches(repoACL) {
|
function logBranches (repoACL) {
|
||||||
console.log('Repo Visibility:', '\t', repoACL.visibility)
|
console.log('Repo Visibility:', '\t', repoACL.visibility)
|
||||||
console.log('Protected Branch(s):', '\t', repoACL.protectedBranches.join(', '))
|
console.log('Protected Branch(s):', '\t', repoACL.protectedBranches.join(', '))
|
||||||
}
|
}
|
||||||
@@ -32,5 +32,5 @@ module.exports = {
|
|||||||
printACL,
|
printACL,
|
||||||
printACLForUser,
|
printACLForUser,
|
||||||
checkIfGitRepo,
|
checkIfGitRepo,
|
||||||
logBranches,
|
logBranches
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ test('e2e', async t => {
|
|||||||
|
|
||||||
await drive.core.update({ wait: true })
|
await drive.core.update({ wait: true })
|
||||||
|
|
||||||
payload = Buffer.from(JSON.stringify({ body: { url, method: 'get-refs', data: repoName }}))
|
payload = Buffer.from(JSON.stringify({ body: { url, method: 'get-refs', data: repoName } }))
|
||||||
const refsRes = await rpc.request('get-refs', payload)
|
const refsRes = await rpc.request('get-refs', payload)
|
||||||
t.ok(refsRes)
|
t.ok(refsRes)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user