func TestEncodeDecode(t *testing.T) { privateKey := generateKey(t) txn1, rand := trans.NewNameReservation("my-new-repository") txn1e := trans.NewEnvelope(types.EmptyHash(), txn1) txn2, _ := trans.NewNameAllocation("my-new-repository", rand) txn2e := trans.NewEnvelope(types.EmptyHash(), txn2) txn3, _ := trans.NewNameDeallocation("my-new-repository") txn3e := trans.NewEnvelope(types.EmptyHash(), txn3) txn1e.Sign(privateKey) txn2e.Sign(privateKey) txn3e.Sign(privateKey) transactions := []*trans.Envelope{txn1e, txn2e, txn3e} block, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions) if err != nil { t.Errorf("can't create a block because of %v", err) } enc, err := block.Encode() if err != nil { t.Errorf("error while encoding block: %v", err) } block1, err := Decode(enc) if err != nil { t.Errorf("error while encoding block: %v", err) } assert.Equal(t, block, block1, "encoded and decoded block should be identical to the original one") }
func fixtureSampleTransactions(t *testing.T) ([]*transaction.Envelope, *ecdsa.PrivateKey) { privateKey := generateECDSAKey(t) txn1, rand := transaction.NewNameReservation("my-new-repository") txn1e := transaction.NewEnvelope(types.EmptyHash(), txn1) txn1e.Sign(privateKey) txn2, _ := transaction.NewNameAllocation("my-new-repository", rand) txn2e := transaction.NewEnvelope(txn1e.Hash(), txn2) txn2e.Sign(privateKey) txn3, _ := transaction.NewNameDeallocation("my-new-repository") txn3e := transaction.NewEnvelope(txn2e.Hash(), txn3) txn3e.Sign(privateKey) return []*transaction.Envelope{txn1e, txn2e, txn3e}, privateKey }
func (service *NameService) NameAllocation(r *http.Request, args *NameAllocationArgs, reply *NameAllocationReply) error { log := service.log.New("cmp", "api_name") key, err := service.srv.DB.GetKey(args.Alias) if err != nil { return err } if key == nil { return errors.New("can't find the key") } random, err := hex.DecodeString(args.Random) if err != nil { return err } tx, err := transaction.NewNameAllocation(args.Name, random) if err != nil { return err } hash, err := service.srv.DB.GetPreviousEnvelopeHashForPublicKey(&key.PublicKey) if err != nil { log.Error("error while preparing transaction", "err", err) } txe := transaction.NewEnvelope(hash, tx) txe.Sign(key) reply.Id = hex.EncodeToString(txe.Hash()) service.srv.Router.Pub(txe, "/transaction") return nil }
func (service *NameService) NameReservation(r *http.Request, args *NameReservationArgs, reply *NameReservationReply) error { log := service.log.New("cmp", "api_name") key, err := service.srv.DB.GetKey(args.Alias) if err != nil { return err } if key == nil { return errors.New("can't find the key") } tx, random := transaction.NewNameReservation(args.Name) hash, err := service.srv.DB.GetPreviousEnvelopeHashForPublicKey(&key.PublicKey) if err != nil { log.Error("error while preparing transaction", "err", err) } txe := transaction.NewEnvelope(hash, tx) txe.Sign(key) reply.Id = hex.EncodeToString(txe.Hash()) reply.Random = hex.EncodeToString(random) // We save sha(random+name)=txhash to scraps to be able to find // the transaction hash by random and number during allocation service.srv.DB.PutScrap(util.SHA256(append(random, []byte(args.Name)...)), txe.Hash()) service.srv.Router.Pub(txe, "/transaction") return nil }
func TestNewBlock(t *testing.T) { privateKey := generateKey(t) txn1, rand := trans.NewNameReservation("my-new-repository") txn1e := trans.NewEnvelope(types.EmptyHash(), txn1) txn2, _ := trans.NewNameAllocation("my-new-repository", rand) txn2e := trans.NewEnvelope(types.EmptyHash(), txn2) txn3, _ := trans.NewNameDeallocation("my-new-repository") txn3e := trans.NewEnvelope(types.EmptyHash(), txn3) txn1e.Sign(privateKey) txn2e.Sign(privateKey) txn3e.Sign(privateKey) transactions := []*trans.Envelope{txn1e, txn2e, txn3e} block1, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions) if err != nil { t.Errorf("can't create a block because of %v", err) } assert.Equal(t, transactions, block1.Transactions) assert.NotEqual(t, block1.MerkleRootHash, types.EmptyHash()) }
func prepareBAT(srv *context.T, log log15.Logger) *transaction.Envelope { key, err := srv.DB.GetMainKey() if err != nil { log.Error("error while attempting to retrieve main key", "err", err) } if key != nil { bat, err := transaction.NewBlockAttribution() if err != nil { log.Error("error while creating a BAT", "err", err) } else { hash, err := srv.DB.GetPreviousEnvelopeHashForPublicKey(&key.PublicKey) if err != nil { log.Error("error while creating a BAT", "err", err) } bate := transaction.NewEnvelope(hash, bat) bate.Sign(key) return bate } } return nil }
func TestPutGetDeleteTransaction(t *testing.T) { privateKey := generateECDSAKey(t) txn1, _ := transaction.NewNameReservation("my-new-repository") txn1e := transaction.NewEnvelope(types.EmptyHash(), txn1) txn1e.Sign(privateKey) db, err := NewDB("test.db") defer os.Remove("test.db") if err != nil { t.Errorf("error opening database: %v", err) } err = db.PutTransaction(txn1e) if err != nil { t.Errorf("error putting transaction: %v", err) } tx, err := db.GetTransaction(txn1e.Hash()) if err != nil { t.Errorf("error getting transaction: %v", err) } assert.Equal(t, tx, txn1e) err = db.DeleteTransaction(txn1e.Hash()) if err != nil { t.Errorf("error getting transaction: %v", err) } tx, err = db.GetTransaction(txn1e.Hash()) if err != nil { t.Errorf("error getting transaction: %v", err) } assert.Nil(t, tx) }
func SetupGitRoutes(r *mux.Router, srv *context.T, log log15.Logger) { log = log.New("cmp", "git") // Git Server r.Methods("POST").Path("/{repository:.+}/git-upload-pack").HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { log := log.New("cmp", "git-upload-pack") dec := pktline.NewDecoder(req.Body) resp.Header().Add("Cache-Control", "no-cache") resp.Header().Add("Content-Type", "application/x-git-upload-pack-result") enc := pktline.NewEncoder(resp) var wants, haves, common []git.Hash var objects []git.Object wantsRcvd := false for { var pktline []byte if err := dec.Decode(&pktline); err != nil { log.Error("error while decoding pkt-line", "err", err) return } switch { case pktline == nil: switch { case !wantsRcvd: wantsRcvd = true case wantsRcvd: for i := range haves { _, err := readObject(srv, haves[i]) if err == nil { enc.Encode([]byte(fmt.Sprintf("ACK %x common\n", haves[i]))) common = append(common, haves[i]) } else { enc.Encode([]byte("NAK\n")) } } haves = make([]git.Hash, 0) } case bytes.Compare(pktline, []byte("done\n")) == 0: if len(common) == 0 { enc.Encode([]byte("NAK\n")) } goto done default: line := bytes.Split(pktline, []byte{' '}) h := bytes.TrimSuffix(line[1], []byte{10}) hash, err := hex.DecodeString(string(h)) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("error parsing hash %s: %v\n", line[1], err))...)) return } if string(line[0]) == "want" { wants = append(wants, hash) } if string(line[0]) == "have" { haves = append(haves, hash) } } } done: var err error for i := range wants { var objs []git.Object objs, err = processCommit(srv, wants[i], common) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("%s", err))...)) return } objects = append(objects, objs...) } // filter out duplicates seen := make(map[string]bool) filteredObjects := make([]git.Object, 0) for i := range objects { hash := string(objects[i].Hash()) if !seen[hash] { seen[hash] = true filteredObjects = append(filteredObjects, objects[i]) } } // packfile := git.NewPackfile(filteredObjects) err = git.WritePackfile(&sideband64Writer{writer: &pktlineWriter{encoder: enc}, band: 1}, packfile) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("%s", err))...)) return } enc.Encode(append([]byte{1}, pktlineToBytes(nil)...)) enc.Encode(nil) }) r.Methods("POST").Path("/{repository:.+}/git-receive-pack").HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { reponame := mux.Vars(req)["repository"] var lines [][]byte dec := pktline.NewDecoder(req.Body) dec.DecodeUntilFlush(&lines) resp.Header().Add("Cache-Control", "no-cache") resp.Header().Add("Content-Type", "application/x-git-receive-pack-result") enc := pktline.NewEncoder(resp) packfile, err := git.ReadPackfile(req.Body) if err != nil { enc.Encode(append([]byte{1}, pktlineToBytes([]byte(fmt.Sprintf("unpack %v\n", err)))...)) } else { enc.Encode(append([]byte{1}, pktlineToBytes([]byte("unpack ok"))...)) for i := range packfile.Objects { err = git.WriteObject(packfile.Objects[i], path.Join(srv.Config.General.DataPath, "objects")) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("Error while writing object: %v\n", err))...)) } else { srv.Router.Pub(packfile.Objects[i], "/git/object") } } for i := range lines { split := strings.Split(string(lines[i]), " ") old := split[0] new := split[1] ref := strings.TrimRight(split[2], string([]byte{0})) oldHash, err := hex.DecodeString(old) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("Malformed hash %s\n", old))...)) return } newHash, err := hex.DecodeString(new) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("Malformed hash %s\n", new))...)) return } tx := transaction.NewReferenceUpdate(reponame, ref, oldHash, newHash) key, err := srv.DB.GetMainKey() if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("Errow while retrieving main key: %v", err))...)) return } if key == nil { enc.Encode(append([]byte{3}, []byte("No main private key to sign the transaction")...)) return } hash, err := srv.DB.GetPreviousEnvelopeHashForPublicKey(&key.PublicKey) if err != nil { enc.Encode(append([]byte{3}, []byte(fmt.Sprintf("Error while preparing transaction: %v", err))...)) return } txe := transaction.NewEnvelope(hash, tx) txe.Sign(key) enc.Encode(append([]byte{2}, []byte(fmt.Sprintf("[gitchain] Transaction %s\n", txe.Hash()))...)) srv.Router.Pub(txe, "/transaction") enc.Encode(append([]byte{1}, pktlineToBytes([]byte(fmt.Sprintf("ok %s\n", ref)))...)) } } enc.Encode(append([]byte{1}, pktlineToBytes(nil)...)) enc.Encode(nil) }) r.Methods("GET").Path("/{repository:.+}/info/refs").HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { req.ParseForm() service := req.Form["service"][0] reponame := mux.Vars(req)["repository"] repo, err := srv.DB.GetRepository(reponame) if err != nil { log.Error("error while retrieving repository", "repo", reponame, "err", err) resp.WriteHeader(500) return } if repo == nil || repo.Status == repository.PENDING { resp.WriteHeader(404) return } refs, err := srv.DB.ListRefs(reponame) if err != nil { log.Error("error listing refs", "repo", reponame, "err", err) resp.WriteHeader(500) return } reflines := make([][]byte, len(refs)) for i := range refs { ref, err := srv.DB.GetRef(reponame, refs[i]) if err != nil { log.Error("error getting ref", "repo", reponame, "err", err) resp.WriteHeader(500) return } refline := append(append([]byte(hex.EncodeToString(ref)), 32), []byte(refs[i])...) if i == 0 { // append capabilities refline = append(append(refline, 0), capabilities()...) } refline = append(refline, 10) // LF reflines[i] = refline } ref, err := srv.DB.GetRef(reponame, "refs/heads/master") if bytes.Compare(ref, make([]byte, 20)) != 0 { reflines = append(reflines, append(append(append([]byte(hex.EncodeToString(ref)), 32), []byte("HEAD")...), 10)) } resp.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-advertisement", service)) resp.Header().Add("Cache-Control", "no-cache") enc := pktline.NewEncoder(resp) enc.Encode([]byte(fmt.Sprintf("# service=%s\n", service))) enc.Encode(nil) if len(reflines) == 0 { enc.Encode(append(append(append(append([]byte("0000000000000000000000000000000000000000"), 32), nulCapabilities()...), []byte{0, 32, 10}...))) } else { for i := range reflines { enc.Encode(reflines[i]) } } enc.Encode(nil) }) r.Methods("GET").Path("/{repository:.+}/HEAD").HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { reponame := mux.Vars(req)["repository"] ref, err := srv.DB.GetRef(reponame, "refs/heads/master") if err != nil { log.Error("error while retrieving repository HEAD", "repo", reponame, "err", err) resp.WriteHeader(500) return } resp.Header().Add("Content-Type", "text/plain") resp.Header().Add("Cache-Control", "no-cache") resp.Write([]byte(hex.EncodeToString(ref))) }) r.Methods("GET").Path("/{repository:.+}/objects/{hash:.+}").HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { }) }