Premier ACME client library for Go

Overview

acmez - ACME client library for Go

godoc

ACMEz ("ack-measy" or "acme-zee", whichever you prefer) is a fully-compliant RFC 8555 (ACME) implementation in pure Go. It is lightweight, has an elegant Go API, and its retry logic is highly robust against external errors. ACMEz is suitable for large-scale enterprise deployments.

NOTE: This module is for getting certificates, not managing certificates. Most users probably want certificate management (keeping certificates renewed) rather than to interface directly with ACME. Developers who want to use certificates in their long-running Go programs should use CertMagic instead; or, if their program is not written in Go, Caddy can be used to manage certificates (even without running an HTTP or TLS server).

This module has two primary packages:

  • acmez is a high-level wrapper for getting certificates. It implements the ACME order flow described in RFC 8555 including challenge solving using pluggable solvers.
  • acme is a low-level RFC 8555 implementation that provides the fundamental ACME operations, mainly useful if you have advanced or niche requirements.

In other words, the acmez package is porcelain while the acme package is plumbing (to use git's terminology).

Features

  • Simple, elegant Go API
  • Thoroughly documented with spec citations
  • Robust to external errors
  • Structured error values ("problems" as defined in RFC 7807)
  • Smart retries (resilient against network and server hiccups)
  • Challenge plasticity (randomized challenges, and will retry others if one fails)
  • Context cancellation (suitable for high-frequency config changes or reloads)
  • Highly flexible and customizable
  • External Account Binding (EAB) support
  • Tested with multiple ACME CAs (more than just Let's Encrypt)
  • Supports niche aspects of RFC 8555 (such as alt cert chains and account key rollover)
  • Efficient solving of large SAN lists (e.g. for slow DNS record propagation)
  • Utility functions for solving challenges
  • Helpers for RFC 8737 (tls-alpn-01 challenge)

The acmez package is "bring-your-own-solver." It provides helper utilities for http-01, dns-01, and tls-alpn-01 challenges, but does not actually solve them for you. You must write an implementation of acmez.Solver in order to get certificates. How this is done depends on the environment in which you're using this code.

This is not a command line utility either. The goal is to not add more external tooling to already-complex infrastructure: ACME and TLS should be built-in to servers rather than tacked on as an afterthought.

Examples

See the examples folder for tutorials on how to use either package.

History

In 2014, the ISRG was finishing the development of its automated CA infrastructure: the first of its kind to become publicly-trusted, under the name Let's Encrypt, which used a young protocol called ACME to automate domain validation and certificate issuance.

Meanwhile, a project called Caddy was being developed which would be the first and only web server to use HTTPS automatically and by default. To make that possible, another project called lego was commissioned by the Caddy project to become of the first-ever ACME client libraries, and the first client written in Go. It was made by Sebastian Erhart (xenolf), and on day 1 of Let's Encrypt's public beta, Caddy used lego to obtain its first certificate automatically at startup, making Caddy and lego the first-ever integrated ACME client.

Since then, Caddy has seen use in production longer than any other ACME client integration, and is well-known for being one of the most robust and reliable HTTPS implementations available today.

A few years later, Caddy's novel auto-HTTPS logic was extracted into a library called CertMagic to be usable by any Go program. Caddy would continue to use CertMagic, which implemented the certificate automation and management logic on top of the low-level certificate obtain logic that lego provided.

Soon thereafter, the lego project shifted maintainership and the goals and vision of the project diverged from those of Caddy's use case of managing tens of thousands of certificates per instance. Eventually, the original Caddy author announced work on a new ACME client library in Go that exceeded Caddy's harsh requirements for large-scale enterprise deployments, lean builds, and simple API. This work finally came to fruition in 2020 as ACMEz.


(c) 2020 Matthew Holt

Comments
  • When I try to request *.example.com and example.com, it will pending

    When I try to request *.example.com and example.com, it will pending

            client := acmez.Client{
    		Client: &acme.Client{
    			Directory: constants.DefaultCA,
    		},
    		ChallengeSolvers: map[string]acmez.Solver{
    			acme.ChallengeTypeDNS01: &acme_issuer.DNS01Solver{
    				PropagationTimeout: time.Minute * 15,
    				PollingInterval:    time.Second * 10,
    				TTL:                constants.DefaultDnsRecordTTL,
    				DNSProvider:        dnsProvider,
    			},
    		},
    	}
            domains:=[]string{"*.example.com","example.com"}
    	log.Println("-----")
    	log.Printf("%+v\n", domains)
            certs, err := client.ObtainCertificate(context.Background(), account.AcmeAccount, certPrivateKey, domains)
    	if err != nil {
    		log.Println(err)
    		return nil, fmt.Errorf("obtaining certificate: %v", err)
    	}
    	log.Println("====")
    

    it use one dns provider, cloudflare.

    when i try one domain, it's works fine domains:=[]string{"*.example.com"} or domains:=[]string{"example.com"}

    opened by r6c 16
  • add get order method

    add get order method

    I want make an api service for cert request for those who want get certificate use dns TXT records manually, like this steps:

    1. send request and return TXT records
    2. add TXT records manually from their dns servers
    3. solve the challenge
    4. get certificate

    If we do not have a get order method, we can't get the order created from step 1, these will create a lot of invalid new orders, so I want to add a get order method, we just need to set the order's Location prop before call GetOrder method.

    Hope to be merged. I have tested that method works!

    opened by mailbaoer 9
  • Missing License?

    Missing License?

    :wave: If this repo is forked from Lego, should it also be licensed under MIT to match https://github.com/go-acme/lego/blob/master/LICENSE ? If not, what is the license?

    Thanks!

    opened by cpu 6
  • If one of multiple SAN's challenges fails, multiple useless

    If one of multiple SAN's challenges fails, multiple useless "ghost" challenges are presented

    If

    • only one solver is defined (e.g. dns-01)
    • ObtainCertificate is called with multiple SAN's (e.g. "a.example.com", "b.example.com", "c.example.com", "d.example.com")
    • validation of one of the "not-first" SAN fails on the ACME server (not in the client) (e.g. c.example.com),

    then all certificates up to the one that failed will be presented and cleaned up again. No actual solving is done. This means that if there are 100 SAN's requested and the last one fails, 99 completely useless calls will be done to Present and CleanUp (which in turn do more requests to DNS api's etc.)

    Here is a example log with replaced domain where the challenge for c.example.com fails:

    [email protected]/client.go:394      trying to solve challenge       {"identifier": "a.example.com", "challenge_type": "dns-01", "ca": "https://acme-staging-v02.api.letsencrypt.org/directory"}
    daemon/main.go:35       present {"id": "a.example.com", "record": "_acme-challenge.a.example.com", "value": "dJ8PiGOYRZRm9ncUaH9zoV-y4aJqymOCbt9fntmbdAo"}
    [email protected]/client.go:394      trying to solve challenge       {"identifier": "b.example.com", "challenge_type": "dns-01", "ca": "https://acme-staging-v02.api.letsencrypt.org/directory"}
    daemon/main.go:35       present {"id": "b.example.com", "record": "_acme-challenge.b.example.com", "value": "_vJbdqEhAogUIrwOGwiduTWY3vC9ZSrN7_8eQ0kI-78"}
    [email protected]/client.go:394      trying to solve challenge       {"identifier": "c.example.com", "challenge_type": "dns-01", "ca": "https://acme-staging-v02.api.letsencrypt.org/directory"}
    daemon/main.go:35       present {"id": "c.example.com", "record": "_acme-challenge.c.example.com", "value": "ifP-oljAlaX-Zf-yDBxV79mHrABZnXyp1Bx9zX1_LpE"}
    [email protected]/client.go:394      trying to solve challenge       {"identifier": "d.example.com", "challenge_type": "dns-01", "ca": "https://acme-staging-v02.api.letsencrypt.org/directory"}
    daemon/main.go:35       present {"id": "d.example.com", "record": "_acme-challenge.d.example.com", "value": "g3NU4vF2SSNEWWaYHcJ7STO6zU5eQB02drvadyc75UQ"}
    daemon/main.go:49       wait    {"id": "a.example.com", "record": "_acme-challenge.a.example.com", "value": "dJ8PiGOYRZRm9ncUaH9zoV-y4aJqymOCbt9fntmbdAo"}
    [email protected]/client.go:433      challenge accepted      {"identifier": "a.example.com", "challenge_type": "dns-01"}
    daemon/main.go:49       wait    {"id": "b.example.com", "record": "_acme-challenge.b.example.com", "value": "_vJbdqEhAogUIrwOGwiduTWY3vC9ZSrN7_8eQ0kI-78"}
    [email protected]/client.go:433      challenge accepted      {"identifier": "b.example.com", "challenge_type": "dns-01"}
    daemon/main.go:49       wait    {"id": "c.example.com", "record": "_acme-challenge.c.example.com", "value": "ifP-oljAlaX-Zf-yDBxV79mHrABZnXyp1Bx9zX1_LpE"}
    [email protected]/client.go:433      challenge accepted      {"identifier": "c.example.com", "challenge_type": "dns-01"}
    daemon/main.go:49       wait    {"id": "d.example.com", "record": "_acme-challenge.d.example.com", "value": "g3NU4vF2SSNEWWaYHcJ7STO6zU5eQB02drvadyc75UQ"}
    [email protected]/client.go:433      challenge accepted      {"identifier": "d.example.com", "challenge_type": "dns-01"}
    daemon/main.go:90       cleanup {"id": "a.example.com", "record": "_acme-challenge.a.example.com", "value": "dJ8PiGOYRZRm9ncUaH9zoV-y4aJqymOCbt9fntmbdAo"}
    daemon/main.go:90       cleanup {"id": "b.example.com", "record": "_acme-challenge.b.example.com", "value": "_vJbdqEhAogUIrwOGwiduTWY3vC9ZSrN7_8eQ0kI-78"}
    daemon/main.go:90       cleanup {"id": "c.example.com", "record": "_acme-challenge.c.example.com", "value": "ifP-oljAlaX-Zf-yDBxV79mHrABZnXyp1Bx9zX1_LpE"}
    [email protected]/client.go:512      challenge failed        {"identifier": "c.example.com", "challenge_type": "dns-01", "problem": {"type": "urn:ietf:params:acme:error:unauthorized", "title": "", "detail": "Incorrect TXT record \"ifP-oljAlaX-Zf-yDBxV79mHrABZnXyp1Bx9zX1_LpE_fail\" found at _acme-challenge.c.example.com", "instance": "", "subproblems": []}}
    github.com/mholt/acmez.(*Client).pollAuthorization
            /home/simon/go/pkg/mod/github.com/mholt/[email protected]/client.go:512
    github.com/mholt/acmez.(*Client).solveChallenges
            /home/simon/go/pkg/mod/github.com/mholt/[email protected]/client.go:368
    github.com/mholt/acmez.(*Client).ObtainCertificateUsingCSR
            /home/simon/go/pkg/mod/github.com/mholt/[email protected]/client.go:127
    github.com/mholt/acmez.(*Client).ObtainCertificate
            /home/simon/go/pkg/mod/github.com/mholt/[email protected]/client.go:235
    ...
    daemon/main.go:90       cleanup {"id": "d.example.com", "record": "_acme-challenge.d.example.com", "value": "g3NU4vF2SSNEWWaYHcJ7STO6zU5eQB02drvadyc75UQ"}
    [email protected]/client.go:143      validating authorization        {"identifier": "c.example.com", "problem": {"type": "urn:ietf:params:acme:error:unauthorized", "title": "", "detail": "Incorrect TXT record \"ifP-oljAlaX-Zf-yDBxV79mHrABZnXyp1Bx9zX1_LpE_fail\" found at _acme-challenge.c.example.com", "instance": "", "subproblems": []}, "order": "https://acme-staging-v02.api.letsencrypt.org/acme/order/38834018/1399577638", "attempt": 1, "max_attempts": 3}
    github.com/mholt/acmez.(*Client).ObtainCertificateUsingCSR
            /home/simon/go/pkg/mod/github.com/mholt/[email protected]/client.go:143
    github.com/mholt/acmez.(*Client).ObtainCertificate
            /home/simon/go/pkg/mod/github.com/mholt/[email protected]/client.go:235
    ...
    [email protected]/client.go:461      no solver configured    {"challenge_type": "tls-alpn-01"}
    [email protected]/client.go:461      no solver configured    {"challenge_type": "http-01"}
    [email protected]/client.go:394      trying to solve challenge       {"identifier": "a.example.com", "challenge_type": "dns-01", "ca": "https://acme-staging-v02.api.letsencrypt.org/directory"}
    daemon/main.go:35       present {"id": "a.example.com", "record": "_acme-challenge.a.example.com", "value": "qHh2Rep4kRSFiJEQ5x4vKS6OwDz_3A4vbo2qnsCCUY0"}
    [email protected]/client.go:461      no solver configured    {"challenge_type": "tls-alpn-01"}
    [email protected]/client.go:461      no solver configured    {"challenge_type": "http-01"}
    [email protected]/client.go:394      trying to solve challenge       {"identifier": "b.example.com", "challenge_type": "dns-01", "ca": "https://acme-staging-v02.api.letsencrypt.org/directory"}
    daemon/main.go:35       present {"id": "b.example.com", "record": "_acme-challenge.b.example.com", "value": "DmvYmPXjLpSkcdXgn7f_IoTjYqwJmsgIBR9AFyuSxY4"}
    [email protected]/client.go:461      no solver configured    {"challenge_type": "tls-alpn-01"}
    [email protected]/client.go:461      no solver configured    {"challenge_type": "http-01"}
    daemon/main.go:90       cleanup {"id": "a.example.com", "record": "_acme-challenge.a.example.com", "value": "qHh2Rep4kRSFiJEQ5x4vKS6OwDz_3A4vbo2qnsCCUY0"}
    daemon/main.go:90       cleanup {"id": "b.example.com", "record": "_acme-challenge.b.example.com", "value": "DmvYmPXjLpSkcdXgn7f_IoTjYqwJmsgIBR9AFyuSxY4"}
    
    obtaining certificate: solving challenges: c.example.com: no solvers available for remaining challenges (configured=[dns-01] offered=[http-01 dns-01 tls-alpn-01] remaining=[http-01 tls-alpn-01]) (order=https://acme-staging-v02.api.letsencrypt.org/acme/order/38834018/1399583088)
    
    

    After the challenge failed, a.example.com and b.example.com are presented and cleaned up without any attempted solve.

    opened by skirsten 5
  • 同学,您这个项目引入了29个开源组件,存在2个漏洞,辛苦升级一下

    同学,您这个项目引入了29个开源组件,存在2个漏洞,辛苦升级一下

    检测到 mholt/acmez 一共引入了29个开源组件,存在2个漏洞

    漏洞标题:go-yaml < 2.2.8拒绝服务漏洞
    漏洞编号:CVE-2019-11254
    漏洞描述:gopkg.in/yaml.v2是go语言中用于处理yaml格式的包。
    在2.2.8之前的版本中,处理恶意的yaml数据时,会导致CPU资源耗尽。
    漏洞由Kubernetes开发者在fuzz测试中发现并提交修复补丁。
    国家漏洞库信息:https://www.cnvd.org.cn/flaw/show/CNVD-2020-35519
    影响范围:(∞, 2.2.8)
    最小修复版本:2.2.8
    缺陷组件引入路径:github.com/mholt/[email protected]>go.uber.org/[email protected]>github.com/stretchr/[email protected]>gopkg.in/[email protected]
    

    另外还有2个漏洞,详细报告:https://mofeisec.com/jr?p=n6cb08

    invalid 
    opened by ghost 3
  • Prevent retry when remainingChallenges is empty

    Prevent retry when remainingChallenges is empty

    After an error, check if it's possible to retry before returning an retryableErr. That way it return the real error instead of returning "no solvers available for remaining challenges".

    It wasn't my intention, but I think it'll solve #7

    opened by N0Cloud 3
  • Solver does not execute every time

    Solver does not execute every time

    During the test, I found that after the authorization valid passed, it seemed that the solver was not executed when I requested to obtain the certificate again,https://github.com/mholt/acmez/blob/master/client.go#L340 ,Because I didn't save DNS TXT record for the first time,After that, I can't seem to get the record again

    needs info 
    opened by hb0730 3
  • Wrap error from httpReq with %w

    Wrap error from httpReq with %w

    I noticed acmez was using a mixture of %v and %w to wrap errors, which caused problems when I was trying to use errors.As() after calling certain functions.

    I've gone through all the fmt.Errorf() calls, replacing %v with %w where appropriate.

    opened by grahamedgecombe 3
  • More time for success?

    More time for success?

    In https://github.com/mholt/acmez/blob/master/client.go#L114 , does that mean that it will only wait 1 second for LetsEncrypt to respond?

    We have sometimes waited for 10 or 20 seconds. :( Can we send a pull request to change that one line, or am I misunderstanding that line?

    Thanks for an awesome lib!

    opened by codewinch 1
  • Use correct error variable in logging

    Use correct error variable in logging

    This could help investigate more for https://github.com/caddy-dns/route53/issues/15

    Scenario

    • Using Caddy server with DNS01 Challenge on Route53 for wildcard certificate
    • Restarting Caddy gives error and shows error which can be ignored, as it was restarted and has no memory of that record.
    • Certificate fails because the TXT record already exists from previous ACME Challenge.
    • After removing TXT record manually, logs doesn't show error while cleaning up, hence the pull request.

    Logs

    Just before the last log, I removed the TXT record manually and it issued the certificate but didn't log the error.

    {"level":"error","ts":1648681778.6813097,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"*.redacted.com","challenge_type":"dns-01","error":"no memory of presenting a DNS record for redacted.com (probably OK if presenting failed)"}
    {"level":"error","ts":1648703379.4469087,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"*.redacted.com","challenge_type":"dns-01","error":"no memory of presenting a DNS record for redacted.com (probably OK if presenting failed)"}
    {"level":"error","ts":1648707063.9319153,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"*.redacted.com","challenge_type":"dns-01","error":"no memory of presenting a DNS record for redacted.com (probably OK if presenting failed)"}
    {"level":"error","ts":1648707125.6041455,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"*.redacted.com","challenge_type":"dns-01","error":"no memory of presenting a DNS record for redacted.com (probably OK if presenting failed)"}
    {"level":"error","ts":1648707334.841073,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"*.redacted.com","challenge_type":"dns-01"}
    
    opened by dtchanpura 0
  • Valid Retry-after Headers are rejected and cause error

    Valid Retry-after Headers are rejected and cause error

    I have been experimenting with certmagic and a let's encrypt Pebble server and have gottne things to work overall but there I had been getting this error:

    Nov 30 09:58:26 dsdev ds-host[1363]: 1.6698311064858541e+09        error        obtain        could not get certificate from issuer        {"identifier": "sub.domain.develop", "issuer": "127.0.0.1:14000-dir", "error": "[sub.domain.develop] finalizing order https://127.0.0.1:14000/my-order/WkaEgtUJEiIT4hysbU7u5WbAHQiH9wJh8afKlt_iAEU: response had invalid Retry-After header: Wed, 30 Nov 2022 17:58:31 GMT (ca=https://127.0.0.1:14000/dir)"}
    

    After some digging I found that Pebble recently added some Retry-After headers: https://github.com/letsencrypt/pebble/commit/6538ad0ff14b6df73c16fb6a013fe6cadcabef48

    It turns out that it flips a coin and sends the header either as seconds or as a full date time. This is per-spec: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After

    Looking at where the error is thrown shows the problem: acmez expects only seconds and doesn't handle the full date-time case: https://github.com/mholt/acmez/blob/d79cc20fee917611841fc8638e00e47464e14036/acme/http.go#L376-L383

    I'm working on a PR.

    opened by teleclimber 0
  • support for RFC8823(s/mime)

    support for RFC8823(s/mime)

    created for s/mime certificate for smime (RFC8823): problem is for email-reply-00 challenge solver really can't return fast enough for interfacee expections, because acme server need to send challenge mail to us before client can do any solving. a dummy solver and do actual solving+waiting in waiter? would that work?

    opened by orangepizza 3
Releases(v1.0.3)
  • v1.0.3(Jul 5, 2022)

    Minor bug fix and upgrade dependencies.

    What's Changed

    • add get order method by @mailbaoer in https://github.com/mholt/acmez/pull/9
    • Use correct error variable in logging by @dtchanpura in https://github.com/mholt/acmez/pull/11

    New Contributors

    • @mailbaoer made their first contribution in https://github.com/mholt/acmez/pull/9
    • @dtchanpura made their first contribution in https://github.com/mholt/acmez/pull/11

    Full Changelog: https://github.com/mholt/acmez/compare/v1.0.2...v1.0.3

    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Feb 2, 2022)

    Minor patch related to retryable error handling.

    What's Changed

    • Prevent retry when remainingChallenges is empty by @N0Cloud in https://github.com/mholt/acmez/pull/8

    New Contributors

    • @N0Cloud made their first contribution in https://github.com/mholt/acmez/pull/8

    Full Changelog: https://github.com/mholt/acmez/compare/v1.0.1...v1.0.2

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Nov 8, 2021)

  • v1.0.0(Aug 26, 2021)

    After no changes in ~8 months (just a minor tweak to logs / error message), I figure it's time to tag a stable 1.0.

    ACMEz works great. Use it! :)

    Source code(tar.gz)
    Source code(zip)
  • v0.1.3(Jan 23, 2021)

  • v0.1.2(Jan 4, 2021)

  • v0.1.1(Sep 17, 2020)

Owner
Matt Holt
M.S. Computer Science. Author of the Caddy Web Server, CertMagic, Papa Parse, JSON/curl-to-Go, Timeliner, Relica, and more...
Matt Holt
A pure Unix shell script implementing ACME client protocol

An ACME Shell script: acme.sh An ACME protocol client written purely in Shell (Unix shell) language. Full ACME protocol implementation. Support ACME v

acme.sh 29.5k Dec 1, 2022
gproxy is a tiny service/library for creating lets-encrypt/acme secured gRPC and http reverse proxies

gproxy is a reverse proxy service AND library for creating flexible, expression-based, lets-encrypt/acme secured gRPC/http reverse proxies GProxy as a

null 16 Sep 11, 2022
null 11 Jun 23, 2022
Prisma Client Go is an auto-generated and fully type-safe database client

Prisma Client Go Typesafe database access for Go Quickstart • Website • Docs • API reference • Blog • Slack • Twitter Prisma Client Go is an auto-gene

Prisma 1.3k Dec 7, 2022
The Dual-Stack Dynamic DNS client, the world's first dynamic DNS client built for IPv6.

dsddns DsDDNS is the Dual-Stack Dynamic DNS client. A dynamic DNS client keeps your DNS records in sync with the IP addresses associated with your hom

Ryan Young 15 Sep 27, 2022
Go Substrate RPC Client (GSRPC)Go Substrate RPC Client (GSRPC)

Go Substrate RPC Client (GSRPC) Substrate RPC client in Go. It provides APIs and types around Polkadot and any Substrate-based chain RPC calls. This c

Chino Chang 1 Nov 11, 2021
Server and client implementation of the grpc go libraries to perform unary, client streaming, server streaming and full duplex RPCs from gRPC go introduction

Description This is an implementation of a gRPC client and server that provides route guidance from gRPC Basics: Go tutorial. It demonstrates how to u

Joram Wambugu 0 Nov 24, 2021
Godaddy-domains-client-go - Godaddy domains api Client golang - Write automaticly from swagger codegen

Go API client for swagger Overview This API client was generated by the swagger-codegen project. By using the swagger-spec from a remote server, you c

Mickael Stanislas 0 Jan 9, 2022
Tailscale-client-go - A client implementation for the Tailscale HTTP API

tailscale-client-go A client implementation for the Tailscale HTTP API Example p

David Bond 0 Sep 8, 2022
Comunicación de envios de archivos entres cliente-servidor, client-client.

Client - Server - Client Estes es un proyecto simple de comunicacion de envios de archivos del cliente al servidor y viceversamente, y de cliente a cl

Melvin RB 1 Jul 16, 2022
Simple mDNS client/server library in Golang

mdns Simple mDNS client/server library in Golang. mDNS or Multicast DNS can be used to discover services on the local network without the use of an au

HashiCorp 924 Nov 30, 2022
Go Beanstalkd Client Library

#gobeanstalk Go Beanstalkd client library. INSTALL go get github.com/iwanbk/gobeanstalk USAGE Producer import ( "github.com/iwanbk/gobeanstalk" "lo

Iwan Budi Kusnanto 63 Jun 15, 2022
🌧 BitTorrent client and library in Go

rain BitTorrent client and library in Go. Running in production at put.io. Features Core protocol Fast extension Magnet links Multiple trackers UDP tr

Cenk Altı 784 Nov 25, 2022
🐈📦 nyaa.si client library for Go. Fetch Anime, Manga, Music and more torrents

?? ?? go-nyaa nyaa.si client library for Go Built on top of: gofeed - search using RSS colly - scrap torrent details page Original idea: ejnshtein/nya

Ilya Revenko 25 Sep 23, 2022
A minimal filecoin client library

filclient A standalone client library for interacting with the filecoin storage network Features Make storage deals with miners Query storage ask pric

Application Research Group 38 Sep 8, 2022
Go/Golang client library to interact with the Stein API

go-stein This Go / Golang client helps you interact with the Stein API. Stein is a suite of programs to help you turn any Google Sheet to a database.

Nasrul Faizin 4 Aug 23, 2022
GoSNMP is an SNMP client library fully written in Go

GoSNMP is an SNMP client library fully written in Go. It provides Get, GetNext, GetBulk, Walk, BulkWalk, Set and Traps. It supports IPv4 and IPv6, using SNMPv1, SNMPv2c or SNMPv3. Builds are tested against linux/amd64 and linux/386.

Go SNMP 920 Dec 1, 2022
A golang library about socks5, supports all socks5 commands. That Provides server and client and easy to use. Compatible with socks4 and socks4a.

socks5 This is a Golang implementation of the Socks5 protocol library. To see in this SOCKS Protocol Version 5. This library is also compatible with S

chenhao zhang 40 Nov 22, 2022