New upstream version 0.0~git20190224.6dc102d

This commit is contained in:
lair repo key
2019-02-23 21:21:30 -05:00
commit 2e0c27c9a1
4 changed files with 316 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 idk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

12
Makefile Normal file
View File

@ -0,0 +1,12 @@
apt-transport-i2phttp:
go build \
-a \
-tags netgo \
-ldflags '-w -extldflags "-static"'
install: apt-transport-i2phttp
install -m755 apt-transport-i2phttp /usr/lib/apt/methods/i2p
clean:
go clean

35
README.md Normal file
View File

@ -0,0 +1,35 @@
apt-transport-i2phttp, HTTP-based I2P Transport for apt
=======================================================
This is a simple transport for downloading debian packages from a repository
over i2p. It uses the built-in HTTP proxy or one you configure. It's a
modified version of [diocles/apt-tranport-http-golang](https://github.com/diocles/apt-transport-http-golang),
a plain HTTP Transport for apt.
Besides that, I think most would agree that it is simpler to use an apt
transport to detect when a package should be retrieved from an i2p service.
Especially in cases where the user is mixing packages from Tor, I2P, and
Clearnet sources, this process can become confusing and involve configuring
multiple applications along with apt. Instead, apt-transport-i2phttp works with
other apt transports like apt-transport-tor and even apt-transport-i2p(A SAM
based alternate i2p transport), requiring no configuration on the vast majority
of systems.
To install it:
--------------
As long as you have an i2p router installed the http proxy should be enabled
by default. You can just:
make build && sudo make install
to install ./apt-transport-i2phttp to /usr/lib/apt/methods/i2p, requiring no
additional configuration.
To use it:
---------
To add an eepSite to your sources.list, for example(This example site is down,
I'll have a new one for you to use shortly):
deb i2p://http://wnhxwrq4fkn3cov6bnqsdaniubeo3625rmsm53yaz336bxvtiqeq.b32.i2p/deb-pkg rolling main

248
main.go Normal file
View File

@ -0,0 +1,248 @@
package main
import (
"bufio"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"strings"
)
type Message struct {
Status string
StatusCode int
Header Header
Exit int
}
type Header map[string][]string
func (h Header) Add(key, value string) {
h[key] = append(h[key], value)
}
func (h Header) Get(key string) string {
if value, ok := h[key]; ok {
if len(value) > 0 {
return value[0]
}
}
return ""
}
func (m *Message) String() string {
s := []string{m.Status}
for k, values := range m.Header {
for _, v := range values {
s = append(s, k+": "+v)
}
}
return strings.Join(s, "\n") + "\n\n"
}
func ReadInConfig() {
if os.Getenv("APT_TRANSPORT_I2PHTTP_CONF") == "" {
os.Setenv("APT_TRANSPORT_I2PHTTP_CONF", "/etc/apt-transport-i2phttp/i2p.conf")
} else {
os.Setenv("APT_TRANSPORT_I2PHTTP_CONF", os.Getenv("APT_TRANSPORT_I2PHTTP_CONF"))
}
if _, err := os.Stat(os.Getenv("APT_TRANSPORT_I2PHTTP_CONF")); os.IsNotExist(err) {
os.Setenv("I2P_HTTP_PROXY", "http://127.0.0.1:4444")
os.Setenv("HTTP_PROXY", "http://127.0.0.1:4444")
} else if err != nil {
log.Fatal(err)
} else {
bytes, err := ioutil.ReadFile(os.Getenv("APT_TRANSPORT_I2PHTTP_CONF"))
if err != nil {
log.Fatal(err)
}
host := "127.0.0.1"
port := "4444"
for _, val := range strings.Split(string(bytes), "\n") {
v := strings.Split(val, "=")
if len(v) == 2 {
if v[0] == "host" {
host = v[0]
}
if v[0] == "port" {
port = v[0]
}
}
}
os.Setenv("I2P_HTTP_PROXY", "http://"+host+":"+port)
os.Setenv("HTTP_PROXY", "http://"+host+":"+port)
}
if os.Getenv("I2P_HTTP_PROXY") == "" {
os.Setenv("I2P_HTTP_PROXY", "http://127.0.0.1:4444")
os.Setenv("HTTP_PROXY", "http://127.0.0.1:4444")
} else {
os.Setenv("HTTP_PROXY", os.Getenv("I2P_HTTP_PROXY"))
}
}
func main() {
ReadInConfig()
c := make(chan *Message)
go output(c)
sendCapabilities(c)
stdin := bufio.NewScanner(os.Stdin)
for stdin.Scan() {
line := stdin.Text()
if line == "" {
continue
}
s := strings.SplitN(line, " ", 2)
code, err := strconv.Atoi(s[0])
if err != nil {
fmt.Println("Malformed message!")
os.Exit(100)
}
request := &Message{
Status: line,
StatusCode: code,
Header: Header{},
}
for stdin.Scan() {
line := stdin.Text()
if line == "" {
process(c, request)
break
}
s := strings.SplitN(line, ": ", 2)
request.Header.Add(s[0], s[1])
}
}
}
func output(c <-chan *Message) {
for {
m := <-c
os.Stdout.Write([]byte(m.String()))
if m.Exit != 0 {
os.Exit(m.Exit)
}
}
}
func sendCapabilities(c chan<- *Message) {
caps := &Message{
Status: "100 Capabilities",
Header: Header{},
}
caps.Header.Add("Version", "1.2")
caps.Header.Add("Pipeline", "true")
caps.Header.Add("Send-Config", "true")
c <- caps
}
func process(c chan<- *Message, m *Message) {
switch m.StatusCode {
case 600:
go fetch(c, m)
case 601:
// TODO: parse config?
default:
fail := &Message{
Status: "401 General Failure",
Header: Header{},
Exit: 100,
}
fail.Header.Add("Message", "Status code not implemented")
c <- fail
}
}
func fetch(c chan<- *Message, m *Message) {
uri := m.Header.Get("URI")
filename := m.Header.Get("Filename")
// TODO: If-Modified-Since
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
c <- &Message{
Status: "400 URI Failure",
Header: Header{
"Message": []string{"Could not open file: " + err.Error()},
"URI": []string{uri},
},
}
return
}
defer file.Close()
// TODO: Fix bug with appending to existing files
// TODO: implement range requests if file already exists
realURI := strings.TrimPrefix(uri, "i2p://")
resp, err := http.Get(realURI)
if err != nil {
c <- &Message{
Status: "400 URI Failure",
Header: Header{
"Message": []string{"Could not fetch URI: " + err.Error()},
"URI": []string{uri},
},
}
return
}
defer resp.Body.Close()
started := &Message{
Status: "200 URI Start",
Header: Header{
"URI": []string{uri},
},
}
// TODO: add Last-Modified header
c <- started
md5Hash := md5.New()
sha1Hash := sha1.New()
sha256Hash := sha256.New()
sha512Hash := sha512.New()
if _, err = io.Copy(io.MultiWriter(file, md5Hash, sha1Hash, sha256Hash, sha512Hash), resp.Body); err != nil {
c <- &Message{
Status: "400 URI Failure",
Header: Header{
"Message": []string{"Could not write file: " + err.Error()},
"URI": []string{uri},
},
}
return
}
success := &Message{
Status: "201 URI Done",
Header: Header{},
}
success.Header.Add("URI", uri)
success.Header.Add("Filename", filename)
// TODO Size, Last-Modified
md5Hex := hex.EncodeToString(md5Hash.Sum(nil)[:])
success.Header.Add("MD5-Hash", md5Hex)
success.Header.Add("MD5Sum-Hash", md5Hex)
success.Header.Add("SHA1-Hash", hex.EncodeToString(sha1Hash.Sum(nil)[:]))
success.Header.Add("SHA256-Hash", hex.EncodeToString(sha256Hash.Sum(nil)[:]))
success.Header.Add("SHA512-Hash", hex.EncodeToString(sha512Hash.Sum(nil)[:]))
c <- success
}