Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cda19e0e82 | ||
![]() |
5010986b65 | ||
![]() |
b216e9fc86 | ||
![]() |
f10e74f03a | ||
![]() |
900f5393ad | ||
![]() |
633a864a02 | ||
![]() |
9cbfbcd4c7 | ||
![]() |
2a96d0ea8f | ||
![]() |
5f80e35560 | ||
![]() |
6848baecce | ||
![]() |
0891cbffe0 | ||
![]() |
c8548ec53a | ||
![]() |
a439c971e8 | ||
![]() |
25363e06ac | ||
![]() |
d2ace7d0b9 | ||
![]() |
de00b9a871 | ||
![]() |
e2a92ffa47 | ||
![]() |
77ccfe94f3 | ||
![]() |
b4236a4201 | ||
![]() |
f1194c38b3 | ||
![]() |
cfdb60d932 | ||
![]() |
6eca8863f7 | ||
![]() |
40ad754b47 | ||
![]() |
6aed9d7cec | ||
![]() |
35e4ae3c89 | ||
![]() |
564a060ed3 | ||
![]() |
62cade9ebc | ||
![]() |
ca305ba46c | ||
![]() |
25eb54b2bc | ||
![]() |
86009cc805 | ||
![]() |
1fc3dc5a20 | ||
![]() |
a2fcfb8bc1 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -24,3 +24,5 @@ itp-golang-github-eyedeekay-gosam.txt
|
|||||||
.pc
|
.pc
|
||||||
deb/
|
deb/
|
||||||
samsocks/samsocks
|
samsocks/samsocks
|
||||||
|
*.private
|
||||||
|
*.public.txt
|
357
CONTRIBUTING.html
Normal file
357
CONTRIBUTING.html
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
goSam
|
||||||
|
</title>
|
||||||
|
<meta name="author" content="eyedeekay" />
|
||||||
|
<meta name="description" content="goSam" />
|
||||||
|
<meta name="keywords" content="master" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="navbar">
|
||||||
|
<a href="#shownav">
|
||||||
|
Show navigation
|
||||||
|
</a>
|
||||||
|
<div id="shownav">
|
||||||
|
<div id="hidenav">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="..">
|
||||||
|
Up one level ^
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="index.html">
|
||||||
|
index
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="CONTRIBUTING.html">
|
||||||
|
CONTRIBUTING
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<a href="#hidenav">
|
||||||
|
Hide Navigation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a id="returnhome" href="/">
|
||||||
|
/
|
||||||
|
</a>
|
||||||
|
<h1>
|
||||||
|
How to make contributions to goSam
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Welcome to goSam, the easy-to-use http client for i2p. We’re glad you’re here
|
||||||
|
and interested in contributing. Here’s some help getting started.
|
||||||
|
</p>
|
||||||
|
<h2>
|
||||||
|
Table of Contents
|
||||||
|
</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
(1) Environment
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
(2) Testing
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
(3) Filing Issues/Reporting Bugs/Making Suggestions
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
(4) Contributing Code/Style Guide
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
(a) Adding i2cp and tunnel Options
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
(b) Writing Tests
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
© Style
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
(d) Other kinds of modification?
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
(5) Conduct
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h3>
|
||||||
|
(1) Environment
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
goSam is a simple go library. You are free to use an IDE if you wish, but all
|
||||||
|
that is required to build and test the library are a go compiler and the gofmt
|
||||||
|
tool. Git is the version control system. All the files in the library are in a
|
||||||
|
single root directory. Invoking go build from this directory not generate any
|
||||||
|
files.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
(2) Testing
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Tests are implemented using the standard go “testing” library in files named
|
||||||
|
“file_test.go,” so tests of the client go in client_test.go, name lookups
|
||||||
|
in naming_test.go, et cetera. Everything that can be tested, should be tested.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Testing is done by running
|
||||||
|
</p>
|
||||||
|
<pre><code> go test
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
More information about designing tests is below in the
|
||||||
|
<strong>
|
||||||
|
Contributing Code/Style Guide
|
||||||
|
</strong>
|
||||||
|
section below.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
(3) Filing issues/Reporting bugs/Making suggestions
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
If you discover the library doing something you don’t think is right, please let
|
||||||
|
us know! Just filing an issue here is OK.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you need to suggest a feature, we’re happy to hear from you too. Filing an
|
||||||
|
issue will give us a place to discuss how it’s implemented openly and publicly.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Please file an issue for your new code contributions in order to provide us with
|
||||||
|
a place to discuss them for inclusion.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
(4) Contributing Code/Style Guide
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Welcome new coders. We have good news for you, this library is really easy to
|
||||||
|
contribute to. The easiest contributions take the form of i2cp and tunnel
|
||||||
|
options.
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
(a) Adding i2cp and tunnel Options
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
First, add a variable to store the state of your new option. For example, the
|
||||||
|
existing variables are in the Client class
|
||||||
|
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/client.go#L29">
|
||||||
|
here:
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
i2cp and tunnel options are added in a highly uniform process of basically three
|
||||||
|
steps. First, you create a functional argument in the options.go file, in the
|
||||||
|
form:
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-Go"> // SetOPTION sets $OPTION
|
||||||
|
func SetOPTION(arg type) func(*Client) error { // arg type
|
||||||
|
return func(c *Client) error { // pass a client to the inner function and declare error return function
|
||||||
|
if arg == valid { // validate the argument
|
||||||
|
c.option = s // set the variable to the argument value
|
||||||
|
return nil // if option is set successfully return nil error
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Invalid argument:" arg) // return a descriptive error if arg is invalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L187">
|
||||||
|
example
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Next, you create a getter which prepares the option. Regardless of the type of
|
||||||
|
option that is set, these must return strings representing valid i2cp options.
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-Go"> //return the OPTION as a string.
|
||||||
|
func (c *Client) option() string {
|
||||||
|
return fmt.Sprintf("i2cp.option=%d", c.option)
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L299">
|
||||||
|
example
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lastly, you’ll need to add it to the allOptions function and the
|
||||||
|
Client.NewClient() function. To add it to allOptions, it looks like this:
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-Go"> //return all options as string ready for passing to sendcmd
|
||||||
|
func (c *Client) allOptions() string {
|
||||||
|
return c.inlength() + " " +
|
||||||
|
c.outlength() + " " +
|
||||||
|
... //other options removed from example for brevity
|
||||||
|
c.option()
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<pre><code class="language-Go"> //return all options as string ready for passing to sendcmd
|
||||||
|
func (c *Client) NewClient() (*Client, error) {
|
||||||
|
return NewClientFromOptions(
|
||||||
|
SetHost(c.host),
|
||||||
|
SetPort(c.port),
|
||||||
|
... //other options removed from example for brevity
|
||||||
|
SetCompression(c.compression),
|
||||||
|
setlastaddr(c.lastaddr),
|
||||||
|
setid(c.id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L333">
|
||||||
|
example
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
(b) Writing Tests
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
Before the feature can be added, you’ll need to add a test for it to
|
||||||
|
options_test.go. To do this, just add your new option to the long TestOptions
|
||||||
|
functions in options_test.go.
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-Go"> func TestOptionHost(t *testing.T) {
|
||||||
|
client, err := NewClientFromOptions(
|
||||||
|
SetHost("127.0.0.1"),
|
||||||
|
SetPort("7656"),
|
||||||
|
... //other options removed from example for brevity
|
||||||
|
SetCloseIdleTime(300001),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
if result, err := client.validCreate(); err != nil {
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
} else {
|
||||||
|
t.Log(result)
|
||||||
|
}
|
||||||
|
client.CreateStreamSession("")
|
||||||
|
if err := client.Close(); err != nil {
|
||||||
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOptionPortInt(t *testing.T) {
|
||||||
|
client, err := NewClientFromOptions(
|
||||||
|
SetHost("127.0.0.1"),
|
||||||
|
SetPortInt(7656),
|
||||||
|
... //other options removed from example for brevity
|
||||||
|
SetUnpublished(true),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
if result, err := client.validCreate(); err != nil {
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
} else {
|
||||||
|
t.Log(result)
|
||||||
|
}
|
||||||
|
client.CreateStreamSession("")
|
||||||
|
if err := client.Close(); err != nil {
|
||||||
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
If any of these tasks fail, then the test should fail.
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
© Style
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
It’s pretty simple to make sure the code style is right, just run gofmt over it
|
||||||
|
to adjust the indentation, and golint over it to ensure that your comments are
|
||||||
|
of the correct form for the documentation generator.
|
||||||
|
</p>
|
||||||
|
<h4>
|
||||||
|
(d) Other kinds of modification?
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
It may be useful to extend goSam in other ways. Since there’s not a
|
||||||
|
one-size-fits-all uniform way of dealing with these kinds of changes, open an
|
||||||
|
issue for discussion and
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
(5) Conduct
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
This is a small-ish, straightforward library intended to enable a clear
|
||||||
|
technical task. We should be able to be civil with eachother, and give and
|
||||||
|
accept criticism contructively and respectfully.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This document was drawn from the examples given by Mozilla
|
||||||
|
<a href="mozillascience.github.io/working-open-workshop/contributing/">
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<div id="sourcecode">
|
||||||
|
<span id="sourcehead">
|
||||||
|
<strong>
|
||||||
|
Get the source code:
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/eyedeekay/goSam">
|
||||||
|
Source Repository: (https://github.com/eyedeekay/goSam)
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="#show">
|
||||||
|
Show license
|
||||||
|
</a>
|
||||||
|
<div id="show">
|
||||||
|
<div id="hide">
|
||||||
|
<pre><code>The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Henry
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<a href="#hide">
|
||||||
|
Hide license
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="https://geti2p.net/">
|
||||||
|
<img src="i2plogo.png"></img>
|
||||||
|
I2P
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
6
Makefile
6
Makefile
@@ -1,16 +1,16 @@
|
|||||||
|
|
||||||
USER_GH=eyedeekay
|
USER_GH=eyedeekay
|
||||||
VERSION=0.32.5
|
VERSION=0.32.7
|
||||||
packagename=gosam
|
packagename=gosam
|
||||||
|
|
||||||
echo: fmt
|
echo: fmt
|
||||||
@echo "type make version to do release $(VERSION)"
|
@echo "type make version to do release $(VERSION)"
|
||||||
|
|
||||||
version:
|
version:
|
||||||
gothub release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)"
|
github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)"
|
||||||
|
|
||||||
del:
|
del:
|
||||||
gothub delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
|
github-release delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
|
||||||
|
|
||||||
tar:
|
tar:
|
||||||
tar --exclude .git \
|
tar --exclude .git \
|
||||||
|
49
README.md
49
README.md
@@ -5,8 +5,9 @@ A go library for using the [I2P](https://geti2p.net/en/) Simple Anonymous
|
|||||||
Messaging ([SAM version 3.0](https://geti2p.net/en/docs/api/samv3)) bridge. It
|
Messaging ([SAM version 3.0](https://geti2p.net/en/docs/api/samv3)) bridge. It
|
||||||
has support for all streaming features SAM version 3.2.
|
has support for all streaming features SAM version 3.2.
|
||||||
|
|
||||||
This is widely used and easy to use, but thusfar, mostly by me. It sees a lot of
|
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days. I am primarily maintaining functionality. This is widely used and easy to use, but thusfar, mostly by me. It sees a lot of testing and no breaking changes to the API are expected.
|
||||||
testing and no breaking changes to the API are expected.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```
|
```
|
||||||
@@ -26,7 +27,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/cryptix/goSam"
|
"github.com/eyedeekay/goSam"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -63,6 +64,47 @@ func main() {
|
|||||||
log.Println("Done.")
|
log.Println("Done.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using SAM by default, as a proxy for all HTTP Clients used by a Go application
|
||||||
|
|
||||||
|
This will make the SAM transport dialer the default for all HTTP clients.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/eyedeekay/goSam"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sam, err := goSam.NewDefaultClient()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
log.Println("Client Created")
|
||||||
|
|
||||||
|
// create a transport that uses SAM to dial TCP Connections
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: sam.Dial,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
http.DefaultClient = httpClient
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkErr(err error) {
|
func checkErr(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -138,3 +180,4 @@ similar systems.
|
|||||||
* Implement `STREAM FORWARD`
|
* Implement `STREAM FORWARD`
|
||||||
* Implement datagrams (Repliable and Anon)
|
* Implement datagrams (Repliable and Anon)
|
||||||
|
|
||||||
|
|
||||||
|
17
accept.go
17
accept.go
@@ -25,24 +25,23 @@ func (c *Client) Listen() (net.Listener, error) {
|
|||||||
func (c *Client) ListenI2P(dest string) (net.Listener, error) {
|
func (c *Client) ListenI2P(dest string) (net.Listener, error) {
|
||||||
var err error
|
var err error
|
||||||
c.destination, err = c.CreateStreamSession(dest)
|
c.destination, err = c.CreateStreamSession(dest)
|
||||||
|
d := c.destination
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.d == nil {
|
|
||||||
c.d, err = c.NewClient(c.NewID())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Listening on destination:", c.Base32()+".b32.i2p")
|
fmt.Println("Listening on destination:", c.Base32()+".b32.i2p")
|
||||||
|
|
||||||
|
c, err = c.NewClient(c.id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.destination = d
|
||||||
|
|
||||||
if c.debug {
|
if c.debug {
|
||||||
c.SamConn = WrapConn(c.SamConn)
|
c.SamConn = WrapConn(c.SamConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.d, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept accepts a connection on a listening goSam.Client(Implements net.Listener)
|
// Accept accepts a connection on a listening goSam.Client(Implements net.Listener)
|
||||||
|
47
auth.go
Normal file
47
auth.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package goSam
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// SetupAuth sends the AUTH ENABLE command and immediately sets up a new Username and
|
||||||
|
// Password from the arguments
|
||||||
|
func (c *Client) SetupAuth(user, password string) error {
|
||||||
|
r, err := c.sendCmd("AUTH ENABLE\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if r.Topic != "AUTH" {
|
||||||
|
return fmt.Errorf("SetupAuth Unknown Reply: %+v\n", r)
|
||||||
|
}
|
||||||
|
r, err = c.sendCmd("AUTH %s %s\n", user, password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if r.Topic != "AUTH" {
|
||||||
|
return fmt.Errorf("SetupAuth Unknown Reply: %+v\n", r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TeardownAuth sends the AUTH DISABLE command but does not remove the Username and
|
||||||
|
// Password from the client PasswordManager
|
||||||
|
func (c *Client) TeardownAuth() error {
|
||||||
|
r, err := c.sendCmd("AUTH DISABLE\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if r.Topic != "AUTH" {
|
||||||
|
return fmt.Errorf("TeardownAuth Unknown Reply: %+v\n", r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveAuthUser(user string) error {
|
||||||
|
r, err := c.sendCmd("AUTH REMOVE %s\n", user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if r.Topic != "AUTH" {
|
||||||
|
return fmt.Errorf("RemoveAuthUser Unknown Reply: %+v\n", r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
58
auth/main.go
Normal file
58
auth/main.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/eyedeekay/goSam"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
THIS is a freestanding test for SAMv3.2 AUTH commands using goSam. It's
|
||||||
|
intended to be run separate from the other tests so that you don't accidentally end
|
||||||
|
up setting SAM session passwords and leaving them in the PasswordManager if a test
|
||||||
|
fails for some reason before you can remove them.
|
||||||
|
**/
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client, err := goSam.NewClientFromOptions()
|
||||||
|
if err != nil {
|
||||||
|
client, err = goSam.NewClientFromOptions(
|
||||||
|
goSam.SetUser("user"),
|
||||||
|
goSam.SetPass("password"),
|
||||||
|
)
|
||||||
|
fmt.Println("Looks like you restarted the I2P router before sending AUTH DISABLE.")
|
||||||
|
fmt.Println("This probably means that your SAM Bridge is in a broken state where it can't")
|
||||||
|
fmt.Println("accept HELLO or AUTH commands anymore. You should fix this by removing the")
|
||||||
|
fmt.Println("sam.auth=true entry from sam.config.")
|
||||||
|
err = client.TeardownAuth()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Println(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = client.SetupAuth("user", "password")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
client2, err := goSam.NewDefaultClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
conn, err := client2.Dial("", "idk.i2p")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
err = client.RemoveAuthUser("user")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
//fmt.Println(r)
|
||||||
|
err = client.TeardownAuth()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
//r, err = client.NewDestination()
|
||||||
|
}
|
39
client.go
39
client.go
@@ -14,7 +14,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
samkeys "github.com/eyedeekay/goSam/compat"
|
"github.com/eyedeekay/i2pkeys"
|
||||||
|
//samkeys "github.com/eyedeekay/goSam/compat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Client represents a single Connection to the SAM bridge
|
// A Client represents a single Connection to the SAM bridge
|
||||||
@@ -23,11 +24,13 @@ type Client struct {
|
|||||||
port string
|
port string
|
||||||
fromport string
|
fromport string
|
||||||
toport string
|
toport string
|
||||||
|
user string
|
||||||
|
pass string
|
||||||
|
|
||||||
SamConn net.Conn // Control socket
|
SamConn net.Conn // Control socket
|
||||||
SamDGConn DatagramConn // Datagram socket
|
SamDGConn net.PacketConn // Datagram socket
|
||||||
rd *bufio.Reader
|
rd *bufio.Reader
|
||||||
d *Client
|
// d *Client
|
||||||
|
|
||||||
sigType string
|
sigType string
|
||||||
destination string
|
destination string
|
||||||
@@ -93,11 +96,16 @@ func NewClient(addr string) (*Client, error) {
|
|||||||
return NewClientFromOptions(SetAddr(addr))
|
return NewClientFromOptions(SetAddr(addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewID() int32 {
|
||||||
|
id := rand.Int31n(math.MaxInt32)
|
||||||
|
fmt.Printf("Initializing new ID: %d\n", id)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
// NewID generates a random number to use as an tunnel name
|
// NewID generates a random number to use as an tunnel name
|
||||||
func (c *Client) NewID() int32 {
|
func (c *Client) NewID() int32 {
|
||||||
if c.id == 0 {
|
if c.id == 0 {
|
||||||
c.id = rand.Int31n(math.MaxInt32)
|
c.id = NewID()
|
||||||
fmt.Printf("Initializing new ID: %d\n", c.id)
|
|
||||||
}
|
}
|
||||||
return c.id
|
return c.id
|
||||||
}
|
}
|
||||||
@@ -190,25 +198,30 @@ func (p *Client) ID() string {
|
|||||||
|
|
||||||
// Addr returns the address of the client as a net.Addr
|
// Addr returns the address of the client as a net.Addr
|
||||||
func (p *Client) Addr() net.Addr {
|
func (p *Client) Addr() net.Addr {
|
||||||
keys, err := samkeys.DestToKeys(p.Destination())
|
keys := i2pkeys.I2PAddr(p.Destination())
|
||||||
if err != nil {
|
return keys
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return keys.Addr()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Client) LocalAddr() net.Addr {
|
func (p *Client) LocalAddr() net.Addr {
|
||||||
return p.Addr()
|
return p.Addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the combined host:port of the SAM bridge
|
// LocalKeys returns the local keys of the client as a fully-fledged i2pkeys.I2PKeys
|
||||||
|
func (p *Client) PrivateAddr() i2pkeys.I2PKeys {
|
||||||
|
//keys := i2pkeys.I2PAddr(p.Destination())
|
||||||
|
keys := i2pkeys.NewKeys(i2pkeys.I2PAddr(p.base64()), p.Destination())
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the combined host:port of the SAM bridge
|
||||||
func (c *Client) samaddr() string {
|
func (c *Client) samaddr() string {
|
||||||
return fmt.Sprintf("%s:%s", c.host, c.port)
|
return fmt.Sprintf("%s:%s", c.host, c.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the initial handshake command and check that the reply is ok
|
// send the initial handshake command and check that the reply is ok
|
||||||
func (c *Client) hello() error {
|
func (c *Client) hello() error {
|
||||||
r, err := c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d\n", c.sammin, c.sammax)
|
|
||||||
|
r, err := c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d %s %s\n", c.sammin, c.sammax, c.getUser(), c.getPass())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -7,21 +7,20 @@ import "testing"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
// "math"
|
||||||
"math/rand"
|
// "math/rand"
|
||||||
"time"
|
// "time"
|
||||||
//"log"
|
//"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
//"github.com/eyedeekay/sam3/helper"
|
||||||
"github.com/eyedeekay/sam3/helper"
|
//"github.com/eyedeekay/i2pkeys"
|
||||||
"github.com/eyedeekay/sam3/i2pkeys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func HelloServer(w http.ResponseWriter, r *http.Request) {
|
func HelloServer(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompositeClient(t *testing.T) {
|
/*func TestCompositeClient(t *testing.T) {
|
||||||
listener, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys")
|
listener, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Listener() Error: %q\n", err)
|
t.Fatalf("Listener() Error: %q\n", err)
|
||||||
@@ -46,7 +45,7 @@ func TestCompositeClient(t *testing.T) {
|
|||||||
// http.HandleFunc("/", HelloServer)
|
// http.HandleFunc("/", HelloServer)
|
||||||
go http.Serve(listener3, nil)
|
go http.Serve(listener3, nil)
|
||||||
|
|
||||||
sam, err := NewClientFromOptions(SetDebug(true))
|
sam, err := NewClientFromOptions(SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -55,36 +54,41 @@ func TestCompositeClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
defer sam.Close()
|
defer sam.Close()
|
||||||
time.Sleep(time.Second * 30)
|
x := 0
|
||||||
|
for x < 15 {
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
t.Log("waiting a little while for services to register", (30 - (x * 2)))
|
||||||
|
x++
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
resp, err := client.Get("http://" + listener.Addr().(i2pkeys.I2PAddr).Base32())
|
resp, err := client.Get("http://" + listener.Addr().(i2pkeys.I2PAddr).Base32())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Get Error: %q\n", err)
|
t.Fatalf("Get Error test 1: %q\n", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
time.Sleep(time.Second * 15)
|
//time.Sleep(time.Second * 15)
|
||||||
go func() {
|
go func() {
|
||||||
resp, err := client.Get("http://" + listener2.Addr().(i2pkeys.I2PAddr).Base32())
|
resp, err := client.Get("http://" + listener2.Addr().(i2pkeys.I2PAddr).Base32())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Get Error: %q\n", err)
|
t.Fatalf("Get Error test 2: %q\n", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
time.Sleep(time.Second * 15)
|
//time.Sleep(time.Second * 15)
|
||||||
go func() {
|
go func() {
|
||||||
resp, err := client.Get("http://" + listener3.Addr().(i2pkeys.I2PAddr).Base32())
|
resp, err := client.Get("http://" + listener3.Addr().(i2pkeys.I2PAddr).Base32())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Get Error: %q\n", err)
|
t.Fatalf("Get Error test 3: %q\n", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
time.Sleep(time.Second * 45)
|
time.Sleep(time.Second * 45)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
func TestClientHello(t *testing.T) {
|
func TestClientHello(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetDebug(true))
|
client, err := NewClientFromOptions(SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -95,7 +99,7 @@ func TestClientHello(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDestination(t *testing.T) {
|
func TestNewDestination(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetDebug(true))
|
client, err := NewClientFromOptions(SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +0,0 @@
|
|||||||
package samkeys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/eyedeekay/sam3/i2pkeys"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DestToKeys(dest string) (i2pkeys.I2PKeys, error) {
|
|
||||||
addr, err := i2pkeys.NewI2PAddrFromString(dest)
|
|
||||||
if err != nil {
|
|
||||||
return i2pkeys.I2PKeys{}, err
|
|
||||||
}
|
|
||||||
return i2pkeys.NewKeys(addr, dest), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeysToDest(keys i2pkeys.I2PKeys) (string, error) {
|
|
||||||
pksk := strings.SplitN(keys.String(), "\n", 2)
|
|
||||||
if len(pksk) != 2 {
|
|
||||||
return "", fmt.Errorf("Error converting from keys to destination")
|
|
||||||
}
|
|
||||||
return pksk[1], nil
|
|
||||||
}
|
|
63
datagram.go
63
datagram.go
@@ -6,21 +6,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DatagramConn
|
// DatagramConn
|
||||||
type DatagramConn interface {
|
type DatagramConn struct {
|
||||||
ReadFrom(p []byte) (n int, addr net.Addr, err error)
|
RWC
|
||||||
Read(b []byte) (n int, err error)
|
conn net.PacketConn
|
||||||
WriteTo(p []byte, addr net.Addr) (n int, err error)
|
RAddr net.Addr
|
||||||
Write(b []byte) (n int, err error)
|
|
||||||
Close() error
|
|
||||||
LocalAddr() net.Addr
|
|
||||||
RemoteAddr() net.Addr
|
|
||||||
SetDeadline(t time.Time) error
|
|
||||||
SetReadDeadline(t time.Time) error
|
|
||||||
SetWriteDeadline(t time.Time) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// WrapConn wraps a net.PacketConn in a DatagramConn.
|
||||||
var conn DatagramConn = &Client{}
|
func WrapPacketConn(c net.Conn) *Conn {
|
||||||
|
wrap := Conn{
|
||||||
|
conn: c,
|
||||||
|
}
|
||||||
|
wrap.Reader = NewReadLogger("<", c)
|
||||||
|
wrap.Writer = NewWriteLogger(">", c)
|
||||||
|
wrap.RWC.c = c
|
||||||
|
return &wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DatagramConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
|
return d.conn.ReadFrom(p)
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) Read(b []byte) (n int, err error) {
|
||||||
|
n, _, err = d.ReadFrom(b)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
|
return d.conn.WriteTo(p, addr)
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) Write(b []byte) (n int, err error) {
|
||||||
|
n, err = d.WriteTo(b, d.RemoteAddr())
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) Close() error {
|
||||||
|
return d.conn.Close()
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) LocalAddr() net.Addr {
|
||||||
|
return d.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) RemoteAddr() net.Addr {
|
||||||
|
return d.RAddr
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) SetDeadline(t time.Time) error {
|
||||||
|
return d.conn.SetDeadline(t)
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return d.conn.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
func (d *DatagramConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return d.conn.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
*/
|
var dgt net.PacketConn = &DatagramConn{}
|
||||||
|
|
||||||
|
//func (c *Client) DatagramSend()
|
||||||
|
54
dest.go
Normal file
54
dest.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package goSam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func validateKindInner(kind string) string {
|
||||||
|
if strings.HasPrefix(kind, "SIGNATURE_TYPE=") {
|
||||||
|
return kind
|
||||||
|
}
|
||||||
|
return "SIGNATURE_TYPE=" + kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateKind(kind string) (string, error) {
|
||||||
|
//convert kind to int
|
||||||
|
kint, err := strconv.Atoi(kind)
|
||||||
|
if err != nil {
|
||||||
|
for _, k := range SAMsigTypes {
|
||||||
|
if strings.HasSuffix(k, kind) {
|
||||||
|
return validateKindInner(kind), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if kint >= 0 && kint <= 7 {
|
||||||
|
return validateKindInner(kind), nil
|
||||||
|
}
|
||||||
|
return "SIGNATURE_TYPE=7", fmt.Errorf("Invalid sigType: %s", kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a new destination and return the base64 encoded string
|
||||||
|
func (c *Client) NewDestination(kind ...string) (string, string, error) {
|
||||||
|
if len(kind) == 0 {
|
||||||
|
kind = []string{"7"}
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
kind[0], err = validateKind(kind[0])
|
||||||
|
if err != nil {
|
||||||
|
if c.debug {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r, err := c.sendCmd("DEST GENERATE %s\n", kind[0])
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
if r.Topic != "DEST" {
|
||||||
|
return "", "", fmt.Errorf("NewDestination Unknown Reply: %+v\n", r)
|
||||||
|
}
|
||||||
|
return r.Pairs["PRIV"], r.Pairs["PUB"], nil
|
||||||
|
|
||||||
|
}
|
29
dial.go
29
dial.go
@@ -39,7 +39,7 @@ func (c *Client) Dial(network, addr string) (net.Conn, error) {
|
|||||||
return c.DialContext(context.TODO(), network, addr)
|
return c.DialContext(context.TODO(), network, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial implements the net.Dial function and can be used for http.Transport
|
// DialContextFree implements the net.Dial function and can be used for http.Transport
|
||||||
func (c *Client) DialContextFree(network, addr string) (net.Conn, error) {
|
func (c *Client) DialContextFree(network, addr string) (net.Conn, error) {
|
||||||
if network == "tcp" || network == "tcp6" || network == "tcp4" {
|
if network == "tcp" || network == "tcp6" || network == "tcp4" {
|
||||||
return c.DialStreamingContextFree(addr)
|
return c.DialStreamingContextFree(addr)
|
||||||
@@ -55,10 +55,21 @@ func (c *Client) DialContextFree(network, addr string) (net.Conn, error) {
|
|||||||
|
|
||||||
// DialDatagramContextFree is a "Dialer" for "Client-Like" Datagram connections.
|
// DialDatagramContextFree is a "Dialer" for "Client-Like" Datagram connections.
|
||||||
// It is also not finished. If you need datagram support right now, use sam3.
|
// It is also not finished. If you need datagram support right now, use sam3.
|
||||||
func (c *Client) DialDatagramContextFree(addr string) (DatagramConn, error) {
|
func (c *Client) DialDatagramContextFree(addr string) (*DatagramConn, error) {
|
||||||
|
portIdx := strings.Index(addr, ":")
|
||||||
|
if portIdx >= 0 {
|
||||||
|
addr = addr[:portIdx]
|
||||||
|
}
|
||||||
|
addr, err := c.Lookup(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("LOOKUP DIALER ERROR %s %s", addr, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("Datagram support is not finished yet, come back later`")
|
return nil, fmt.Errorf("Datagram support is not finished yet, come back later`")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DialStreamingContextFree is a "Dialer" for "Client-Like" Streaming connections.
|
||||||
func (c *Client) DialStreamingContextFree(addr string) (net.Conn, error) {
|
func (c *Client) DialStreamingContextFree(addr string) (net.Conn, error) {
|
||||||
portIdx := strings.Index(addr, ":")
|
portIdx := strings.Index(addr, ":")
|
||||||
if portIdx >= 0 {
|
if portIdx >= 0 {
|
||||||
@@ -76,16 +87,14 @@ func (c *Client) DialStreamingContextFree(addr string) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.d == nil {
|
|
||||||
c.d, err = c.NewClient(c.NewID())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.d.StreamConnect(addr)
|
d, err := c.NewClient(c.NewID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.d.SamConn, nil
|
err = d.StreamConnect(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.SamConn, nil
|
||||||
}
|
}
|
||||||
|
29
go.mod
29
go.mod
@@ -1,17 +1,24 @@
|
|||||||
module github.com/eyedeekay/goSam
|
module github.com/eyedeekay/goSam
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/eyedeekay/sam3 v0.32.32
|
github.com/eyedeekay/i2pkeys v0.33.0
|
||||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5
|
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5
|
||||||
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9 // indirect
|
|
||||||
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd // indirect
|
|
||||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace github.com/eyedeekay/gosam v0.1.1-0.20190814195658-27e786578944 => github.com/eyedeekay/goSam ./
|
require (
|
||||||
|
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
|
||||||
replace github.com/eyedeekay/gosam v0.32.1 => ./
|
github.com/getlantern/errors v1.0.1 // indirect
|
||||||
|
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65 // indirect
|
||||||
replace github.com/eyedeekay/goSam v0.32.1 => ./
|
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
|
||||||
|
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
|
||||||
go 1.13
|
github.com/getlantern/iptool v0.0.0-20210721034953-519bf8ce0147 // indirect
|
||||||
|
github.com/getlantern/netx v0.0.0-20211206143627-7ccfeb739cbd // indirect
|
||||||
|
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect
|
||||||
|
github.com/go-stack/stack v1.8.0 // indirect
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
go.uber.org/zap v1.19.1 // indirect
|
||||||
|
)
|
||||||
|
84
go.sum
84
go.sum
@@ -1,35 +1,91 @@
|
|||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab h1:EfTRHxGSbiaEyxNzvKRBWVIDw3mD8xXGxj4gvwFzY7Q=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab/go.mod h1:h7mvUAMgZ/rtRDUOkvKTK+8LnDMeUhJSoa5EPdB51fc=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/eyedeekay/sam3 v0.32.2 h1:xODDY5nBVg0oK7KaYk7ofkXFoHPsmI1umhSv1TZlS7s=
|
github.com/eyedeekay/i2pkeys v0.33.0 h1:5SzUyWxNjV6AvYv/WaI8J4dSgAfv7/WEps6pDLe2YSs=
|
||||||
github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
|
github.com/eyedeekay/i2pkeys v0.33.0/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||||
github.com/eyedeekay/sam3 v0.32.31 h1:0fdDAupEQZSETHcyVQAsnFgpYArGJzU+lC2qN6f0GDk=
|
|
||||||
github.com/eyedeekay/sam3 v0.32.32-0.20201122050855-f464873c9350 h1:8R4zcaWsgANiZ4MKKBPUf9Isct2M1IFVUVZdAMqPCmU=
|
|
||||||
github.com/eyedeekay/sam3 v0.32.32-0.20201122050855-f464873c9350/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
|
||||||
github.com/eyedeekay/sam3 v0.32.32 h1:9Ea1Ere5O8Clx8zYxKnvhrWy7R96Q4FvxlPskYf8VW0=
|
|
||||||
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
|
||||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||||
github.com/getlantern/errors v1.0.1 h1:XukU2whlh7OdpxnkXhNH9VTLVz0EVPGKDV5K0oWhvzw=
|
github.com/getlantern/errors v1.0.1 h1:XukU2whlh7OdpxnkXhNH9VTLVz0EVPGKDV5K0oWhvzw=
|
||||||
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||||
|
github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4 h1:JdD4XSaT6/j6InM7MT1E4WRvzR8gurxfq53A3ML3B/Q=
|
||||||
|
github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4/go.mod h1:XZwE+iIlAgr64OFbXKFNCllBwV4wEipPx8Hlo2gZdbM=
|
||||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5 h1:RBKofGGMt2k6eGBwX8mky9qunjL+KnAp9JdzXjiRkRw=
|
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5 h1:RBKofGGMt2k6eGBwX8mky9qunjL+KnAp9JdzXjiRkRw=
|
||||||
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
|
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
|
||||||
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9 h1:8MYJU90rB1bsavemKSAuDKBjtAKo5xq95bEPOnzV7CE=
|
github.com/getlantern/golog v0.0.0-20210606115803-bce9f9fe5a5f/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
|
||||||
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
|
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65 h1:NlQedYmPI3pRAXJb+hLVVDGqfvvXGRPV8vp7XOjKAZ0=
|
||||||
|
github.com/getlantern/golog v0.0.0-20230503153817-8e72de7e0a65/go.mod h1:+ZU1h+iOVqWReBpky6d5Y2WL0sF2Llxu+QcxJFs2+OU=
|
||||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
||||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
||||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||||
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd h1:mn98vs69Kqw56iKhR82mjk16Q1q5aDFFW0E89/QbXkQ=
|
github.com/getlantern/iptool v0.0.0-20210721034953-519bf8ce0147 h1:/4ibPEIbC7c786Ec5Z8QqTti8MAjjTp/LmfuF6frVDM=
|
||||||
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd/go.mod h1:wKdY0ikOgzrWSeB9UyBVKPRhjXQ+vTb+BPeJuypUuNE=
|
github.com/getlantern/iptool v0.0.0-20210721034953-519bf8ce0147/go.mod h1:hfspzdRcvJ130tpTPL53/L92gG0pFtvQ6ln35ppwhHE=
|
||||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
|
github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848 h1:2MhMMVBTnaHrst6HyWFDhwQCaJ05PZuOv1bE2gN8WFY=
|
||||||
|
github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848/go.mod h1:+F5GJ7qGpQ03DBtcOEyQpM30ix4BLswdaojecFtsdy8=
|
||||||
|
github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7 h1:03J6Cb42EG06lHgpOFGm5BOax4qFqlSbSeKO2RGrj2g=
|
||||||
|
github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7/go.mod h1:GfzwugvtH7YcmNIrHHizeyImsgEdyL88YkdnK28B14c=
|
||||||
|
github.com/getlantern/netx v0.0.0-20211206143627-7ccfeb739cbd h1:z5IehLDMqMwJ0oeFIaMHhySRU8r1lRMh7WQ0Wn0LioA=
|
||||||
|
github.com/getlantern/netx v0.0.0-20211206143627-7ccfeb739cbd/go.mod h1:WEXF4pfIfnHBUAKwLa4DW7kcEINtG6wjUkbL2btwXZQ=
|
||||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 h1:QthAQCekS1YOeYWSvoHI6ZatlG4B+GBDLxV/2ZkBsTA=
|
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 h1:QthAQCekS1YOeYWSvoHI6ZatlG4B+GBDLxV/2ZkBsTA=
|
||||||
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
|
||||||
|
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||||
|
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
32
i2pkeys.go
32
i2pkeys.go
@@ -1,32 +0,0 @@
|
|||||||
package goSam
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewDestination generates a new I2P destination, creating the underlying
|
|
||||||
// public/private keys in the process. The public key can be used to send messages
|
|
||||||
// to the destination, while the private key can be used to reply to messages
|
|
||||||
func (c *Client) NewDestination(sigType ...string) (string, string, error) {
|
|
||||||
var (
|
|
||||||
sigtmp string
|
|
||||||
)
|
|
||||||
if len(sigType) > 0 {
|
|
||||||
sigtmp = sigType[0]
|
|
||||||
}
|
|
||||||
r, err := c.sendCmd(
|
|
||||||
"DEST GENERATE %s\n",
|
|
||||||
sigtmp,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
var pub, priv string
|
|
||||||
if priv = r.Pairs["PRIV"]; priv == "" {
|
|
||||||
return "", "", errors.New("failed to generate private destination key")
|
|
||||||
}
|
|
||||||
if pub = r.Pairs["PUB"]; pub == "" {
|
|
||||||
return priv, "", errors.New("failed to generate public destination key")
|
|
||||||
}
|
|
||||||
return priv, pub, nil
|
|
||||||
}
|
|
BIN
i2plogo.png
Normal file
BIN
i2plogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
325
index.html
Normal file
325
index.html
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
goSam
|
||||||
|
</title>
|
||||||
|
<meta name="author" content="eyedeekay" />
|
||||||
|
<meta name="description" content="goSam" />
|
||||||
|
<meta name="keywords" content="master" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="showhider.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="navbar">
|
||||||
|
<a href="#shownav">
|
||||||
|
Show navigation
|
||||||
|
</a>
|
||||||
|
<div id="shownav">
|
||||||
|
<div id="hidenav">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="..">
|
||||||
|
Up one level ^
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="index.html">
|
||||||
|
index
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="CONTRIBUTING.html">
|
||||||
|
CONTRIBUTING
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<a href="#hidenav">
|
||||||
|
Hide Navigation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a id="returnhome" href="/">
|
||||||
|
/
|
||||||
|
</a>
|
||||||
|
<h1>
|
||||||
|
goSam
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
A go library for using the
|
||||||
|
<a href="https://geti2p.net/en/">
|
||||||
|
I2P
|
||||||
|
</a>
|
||||||
|
Simple Anonymous
|
||||||
|
Messaging (
|
||||||
|
<a href="https://geti2p.net/en/docs/api/samv3">
|
||||||
|
SAM version 3.0
|
||||||
|
</a>
|
||||||
|
) bridge. It
|
||||||
|
has support for all streaming features SAM version 3.2.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days. I am primarily maintaining functionality. This is widely used and easy to use, but thusfar, mostly by me. It sees a lot of testing and no breaking changes to the API are expected.
|
||||||
|
</p>
|
||||||
|
<h2>
|
||||||
|
Installation
|
||||||
|
</h2>
|
||||||
|
<pre><code>go get github.com/eyedeekay/goSam
|
||||||
|
</code></pre>
|
||||||
|
<h2>
|
||||||
|
Using it for HTTP Transport
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
<code>
|
||||||
|
Client.Dial
|
||||||
|
</code>
|
||||||
|
implements
|
||||||
|
<code>
|
||||||
|
net.Dial
|
||||||
|
</code>
|
||||||
|
so you can use go’s library packages like http.
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-go">package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/cryptix/goSam"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// create a default sam client
|
||||||
|
sam, err := goSam.NewDefaultClient()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
log.Println("Client Created")
|
||||||
|
|
||||||
|
// create a transport that uses SAM to dial TCP Connections
|
||||||
|
tr := &http.Transport{
|
||||||
|
Dial: sam.Dial,
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a client using this transport
|
||||||
|
client := &http.Client{Transport: tr}
|
||||||
|
|
||||||
|
// send a get request
|
||||||
|
resp, err := client.Get("http://stats.i2p/")
|
||||||
|
checkErr(err)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
log.Printf("Get returned %+v\n", resp)
|
||||||
|
|
||||||
|
// create a file for the response
|
||||||
|
file, err := os.Create("stats.html")
|
||||||
|
checkErr(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// copy the response to the file
|
||||||
|
_, err = io.Copy(file, resp.Body)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
log.Println("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<h3>
|
||||||
|
Using SAM by default, as a proxy for all HTTP Clients used by a Go application
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
This will make the SAM transport dialer the default for all HTTP clients.
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-go">package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/cryptix/goSam"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sam, err := goSam.NewDefaultClient()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
log.Println("Client Created")
|
||||||
|
|
||||||
|
// create a transport that uses SAM to dial TCP Connections
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: sam.Dial,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
http.DefaultClient = httpClient
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h2>
|
||||||
|
Using it as a SOCKS proxy
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
<code>
|
||||||
|
client
|
||||||
|
</code>
|
||||||
|
also implements a resolver compatible with
|
||||||
|
<a href="https://github.com/getlantern/go-socks5">
|
||||||
|
<code>
|
||||||
|
getlantern/go-socks5
|
||||||
|
</code>
|
||||||
|
</a>
|
||||||
|
,
|
||||||
|
making it very easy to implement a SOCKS5 server.
|
||||||
|
</p>
|
||||||
|
<pre><code class="language-go">package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
"github.com/eyedeekay/goSam"
|
||||||
|
"github.com/getlantern/go-socks5"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
samaddr = flag.String("sam", "127.0.0.1:7656", "SAM API address to use")
|
||||||
|
socksaddr = flag.String("socks", "127.0.0.1:7675", "SOCKS address to use")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sam, err := goSam.NewClient(*samaddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Println("Client Created")
|
||||||
|
|
||||||
|
// create a transport that uses SAM to dial TCP Connections
|
||||||
|
conf := &socks5.Config{
|
||||||
|
Dial: sam.DialContext,
|
||||||
|
Resolver: sam,
|
||||||
|
}
|
||||||
|
server, err := socks5.New(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SOCKS5 proxy on localhost port 8000
|
||||||
|
if err := server.ListenAndServe("tcp", *socksaddr); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h3>
|
||||||
|
.deb package
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
A package for installing this on Debian is buildable, and a version for Ubuntu
|
||||||
|
is available as a PPA and mirrored via i2p. To build the deb package, from the
|
||||||
|
root of this repository with the build dependencies installed(git, i2p, go,
|
||||||
|
debuild) run the command
|
||||||
|
</p>
|
||||||
|
<pre><code> debuild -us -uc
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
to produce an unsigned deb for personal use only. For packagers,
|
||||||
|
</p>
|
||||||
|
<pre><code> debuild -S
|
||||||
|
</code></pre>
|
||||||
|
<p>
|
||||||
|
will produce a viable source package for use with Launchpad PPA’s and other
|
||||||
|
similar systems.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
TODO
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Improve recovery on failed sockets
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Implement
|
||||||
|
<code>
|
||||||
|
STREAM FORWARD
|
||||||
|
</code>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Implement datagrams (Repliable and Anon)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div id="sourcecode">
|
||||||
|
<span id="sourcehead">
|
||||||
|
<strong>
|
||||||
|
Get the source code:
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/eyedeekay/goSam">
|
||||||
|
Source Repository: (https://github.com/eyedeekay/goSam)
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="#show">
|
||||||
|
Show license
|
||||||
|
</a>
|
||||||
|
<div id="show">
|
||||||
|
<div id="hide">
|
||||||
|
<pre><code>The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Henry
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
</code></pre>
|
||||||
|
<a href="#hide">
|
||||||
|
Hide license
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="https://geti2p.net/">
|
||||||
|
<img src="i2plogo.png"></img>
|
||||||
|
I2P
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -11,7 +11,7 @@ import (
|
|||||||
func TestClientLookupInvalid(t *testing.T) {
|
func TestClientLookupInvalid(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
client, err := NewClientFromOptions(SetDebug(true))
|
client, err := NewClientFromOptions(SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
|
135
options.go
135
options.go
@@ -6,10 +6,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Option is a client Option
|
// Option is a client Option
|
||||||
type Option func(*Client) error
|
type Option func(*Client) error
|
||||||
|
|
||||||
//SetAddr sets a clients's address in the form host:port or host, port
|
// SetAddr sets a clients's address in the form host:port or host, port
|
||||||
func SetAddr(s ...string) func(*Client) error {
|
func SetAddr(s ...string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if len(s) == 1 {
|
if len(s) == 1 {
|
||||||
@@ -42,7 +42,7 @@ func SetAddr(s ...string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetAddrMixed sets a clients's address in the form host, port(int)
|
// SetAddrMixed sets a clients's address in the form host, port(int)
|
||||||
func SetAddrMixed(s string, i int) func(*Client) error {
|
func SetAddrMixed(s string, i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 65536 && i > 0 {
|
if i < 65536 && i > 0 {
|
||||||
@@ -54,7 +54,7 @@ func SetAddrMixed(s string, i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetHost sets the host of the client's SAM bridge
|
// SetHost sets the host of the client's SAM bridge
|
||||||
func SetHost(s string) func(*Client) error {
|
func SetHost(s string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.host = s
|
c.host = s
|
||||||
@@ -62,6 +62,22 @@ func SetHost(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetUser sets the username for authentication during the SAM HELLO phase
|
||||||
|
func SetUser(s string) func(*Client) error {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.user = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUser sets the password for authentication during the SAM HELLO phase
|
||||||
|
func SetPass(s string) func(*Client) error {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.pass = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SetSAMMinVersion(i int) func(*Client) error {
|
func SetSAMMinVersion(i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
@@ -88,8 +104,8 @@ func SetSAMMaxVersion(i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetLocalDestination sets the local destination of the tunnel from a private
|
// SetLocalDestination sets the local destination of the tunnel from a private
|
||||||
//key
|
// key
|
||||||
func SetLocalDestination(s string) func(*Client) error {
|
func SetLocalDestination(s string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.destination = s
|
c.destination = s
|
||||||
@@ -104,7 +120,7 @@ func setid(s int32) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetPort sets the port of the client's SAM bridge using a string
|
// SetPort sets the port of the client's SAM bridge using a string
|
||||||
func SetPort(s string) func(*Client) error {
|
func SetPort(s string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
port, err := strconv.Atoi(s)
|
port, err := strconv.Atoi(s)
|
||||||
@@ -119,7 +135,7 @@ func SetPort(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetPortInt sets the port of the client's SAM bridge using a string
|
// SetPortInt sets the port of the client's SAM bridge using a string
|
||||||
func SetPortInt(i int) func(*Client) error {
|
func SetPortInt(i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 65536 && i > -1 {
|
if i < 65536 && i > -1 {
|
||||||
@@ -130,7 +146,7 @@ func SetPortInt(i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetFromPort sets the port of the client's SAM bridge using a string
|
// SetFromPort sets the port of the client's SAM bridge using a string
|
||||||
func SetFromPort(s string) func(*Client) error {
|
func SetFromPort(s string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
port, err := strconv.Atoi(s)
|
port, err := strconv.Atoi(s)
|
||||||
@@ -145,7 +161,7 @@ func SetFromPort(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetFromPortInt sets the port of the client's SAM bridge using a string
|
// SetFromPortInt sets the port of the client's SAM bridge using a string
|
||||||
func SetFromPortInt(i int) func(*Client) error {
|
func SetFromPortInt(i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 65536 && i > -1 {
|
if i < 65536 && i > -1 {
|
||||||
@@ -156,7 +172,7 @@ func SetFromPortInt(i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetToPort sets the port of the client's SAM bridge using a string
|
// SetToPort sets the port of the client's SAM bridge using a string
|
||||||
func SetToPort(s string) func(*Client) error {
|
func SetToPort(s string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
port, err := strconv.Atoi(s)
|
port, err := strconv.Atoi(s)
|
||||||
@@ -171,7 +187,7 @@ func SetToPort(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetToPortInt sets the port of the client's SAM bridge using a string
|
// SetToPortInt sets the port of the client's SAM bridge using a string
|
||||||
func SetToPortInt(i int) func(*Client) error {
|
func SetToPortInt(i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 65536 && i > -1 {
|
if i < 65536 && i > -1 {
|
||||||
@@ -182,15 +198,16 @@ func SetToPortInt(i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetDebug enables debugging messages
|
// SetDebug enables debugging messages
|
||||||
func SetDebug(b bool) func(*Client) error {
|
func SetDebug(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.debug = b
|
//c.debug = b
|
||||||
|
c.debug = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetInLength sets the number of hops inbound
|
// SetInLength sets the number of hops inbound
|
||||||
func SetInLength(u uint) func(*Client) error {
|
func SetInLength(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u < 7 {
|
if u < 7 {
|
||||||
@@ -201,7 +218,7 @@ func SetInLength(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetOutLength sets the number of hops outbound
|
// SetOutLength sets the number of hops outbound
|
||||||
func SetOutLength(u uint) func(*Client) error {
|
func SetOutLength(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u < 7 {
|
if u < 7 {
|
||||||
@@ -212,7 +229,7 @@ func SetOutLength(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetInVariance sets the variance of a number of hops inbound
|
// SetInVariance sets the variance of a number of hops inbound
|
||||||
func SetInVariance(i int) func(*Client) error {
|
func SetInVariance(i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 7 && i > -7 {
|
if i < 7 && i > -7 {
|
||||||
@@ -223,7 +240,7 @@ func SetInVariance(i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetOutVariance sets the variance of a number of hops outbound
|
// SetOutVariance sets the variance of a number of hops outbound
|
||||||
func SetOutVariance(i int) func(*Client) error {
|
func SetOutVariance(i int) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if i < 7 && i > -7 {
|
if i < 7 && i > -7 {
|
||||||
@@ -234,7 +251,7 @@ func SetOutVariance(i int) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetInQuantity sets the inbound tunnel quantity
|
// SetInQuantity sets the inbound tunnel quantity
|
||||||
func SetInQuantity(u uint) func(*Client) error {
|
func SetInQuantity(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u <= 16 {
|
if u <= 16 {
|
||||||
@@ -245,7 +262,7 @@ func SetInQuantity(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetOutQuantity sets the outbound tunnel quantity
|
// SetOutQuantity sets the outbound tunnel quantity
|
||||||
func SetOutQuantity(u uint) func(*Client) error {
|
func SetOutQuantity(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u <= 16 {
|
if u <= 16 {
|
||||||
@@ -256,7 +273,7 @@ func SetOutQuantity(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetInBackups sets the inbound tunnel backups
|
// SetInBackups sets the inbound tunnel backups
|
||||||
func SetInBackups(u uint) func(*Client) error {
|
func SetInBackups(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u < 6 {
|
if u < 6 {
|
||||||
@@ -267,7 +284,7 @@ func SetInBackups(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetOutBackups sets the inbound tunnel backups
|
// SetOutBackups sets the inbound tunnel backups
|
||||||
func SetOutBackups(u uint) func(*Client) error {
|
func SetOutBackups(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u < 6 {
|
if u < 6 {
|
||||||
@@ -278,7 +295,7 @@ func SetOutBackups(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetUnpublished tells the router to not publish the client leaseset
|
// SetUnpublished tells the router to not publish the client leaseset
|
||||||
func SetUnpublished(b bool) func(*Client) error {
|
func SetUnpublished(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.dontPublishLease = b
|
c.dontPublishLease = b
|
||||||
@@ -286,7 +303,7 @@ func SetUnpublished(b bool) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetEncrypt tells the router to use an encrypted leaseset
|
// SetEncrypt tells the router to use an encrypted leaseset
|
||||||
func SetEncrypt(b bool) func(*Client) error {
|
func SetEncrypt(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.encryptLease = b
|
c.encryptLease = b
|
||||||
@@ -294,8 +311,8 @@ func SetEncrypt(b bool) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetLeaseSetEncType tells the router to use an encrypted leaseset of a specific type.
|
// SetLeaseSetEncType tells the router to use an encrypted leaseset of a specific type.
|
||||||
//defaults to 4,0
|
// defaults to 4,0
|
||||||
func SetLeaseSetEncType(b string) func(*Client) error {
|
func SetLeaseSetEncType(b string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.leaseSetEncType = b
|
c.leaseSetEncType = b
|
||||||
@@ -303,7 +320,7 @@ func SetLeaseSetEncType(b string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetReduceIdle sets the created tunnels to be reduced during extended idle time to avoid excessive resource usage
|
// SetReduceIdle sets the created tunnels to be reduced during extended idle time to avoid excessive resource usage
|
||||||
func SetReduceIdle(b bool) func(*Client) error {
|
func SetReduceIdle(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.reduceIdle = b
|
c.reduceIdle = b
|
||||||
@@ -311,7 +328,7 @@ func SetReduceIdle(b bool) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetReduceIdleTime sets time to wait before the tunnel quantity is reduced
|
// SetReduceIdleTime sets time to wait before the tunnel quantity is reduced
|
||||||
func SetReduceIdleTime(u uint) func(*Client) error {
|
func SetReduceIdleTime(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u > 299999 {
|
if u > 299999 {
|
||||||
@@ -322,7 +339,7 @@ func SetReduceIdleTime(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetReduceIdleQuantity sets number of tunnels to keep alive during an extended idle period
|
// SetReduceIdleQuantity sets number of tunnels to keep alive during an extended idle period
|
||||||
func SetReduceIdleQuantity(u uint) func(*Client) error {
|
func SetReduceIdleQuantity(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u < 5 {
|
if u < 5 {
|
||||||
@@ -333,7 +350,7 @@ func SetReduceIdleQuantity(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetCloseIdle sets the tunnels to close after a specific amount of time
|
// SetCloseIdle sets the tunnels to close after a specific amount of time
|
||||||
func SetCloseIdle(b bool) func(*Client) error {
|
func SetCloseIdle(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.closeIdle = b
|
c.closeIdle = b
|
||||||
@@ -341,7 +358,7 @@ func SetCloseIdle(b bool) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetCloseIdleTime sets the time in milliseconds to wait before closing tunnels
|
// SetCloseIdleTime sets the time in milliseconds to wait before closing tunnels
|
||||||
func SetCloseIdleTime(u uint) func(*Client) error {
|
func SetCloseIdleTime(u uint) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if u > 299999 {
|
if u > 299999 {
|
||||||
@@ -352,7 +369,7 @@ func SetCloseIdleTime(u uint) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetCompression sets the tunnels to close after a specific amount of time
|
// SetCompression sets the tunnels to close after a specific amount of time
|
||||||
func SetCompression(b bool) func(*Client) error {
|
func SetCompression(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.compression = b
|
c.compression = b
|
||||||
@@ -362,13 +379,15 @@ func SetCompression(b bool) func(*Client) error {
|
|||||||
|
|
||||||
/* SAM v 3.1 Options*/
|
/* SAM v 3.1 Options*/
|
||||||
|
|
||||||
//SetSignatureType tells gosam to pass SAM a signature_type parameter with one
|
// SetSignatureType tells gosam to pass SAM a signature_type parameter with one
|
||||||
// of the following values:
|
// of the following values:
|
||||||
// "SIGNATURE_TYPE=DSA_SHA1",
|
//
|
||||||
// "SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
// "SIGNATURE_TYPE=DSA_SHA1",
|
||||||
// "SIGNATURE_TYPE=ECDSA_SHA384_P384",
|
// "SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
||||||
// "SIGNATURE_TYPE=ECDSA_SHA512_P521",
|
// "SIGNATURE_TYPE=ECDSA_SHA384_P384",
|
||||||
// "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
// "SIGNATURE_TYPE=ECDSA_SHA512_P521",
|
||||||
|
// "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
||||||
|
//
|
||||||
// or an empty string
|
// or an empty string
|
||||||
func SetSignatureType(s string) func(*Client) error {
|
func SetSignatureType(s string) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
@@ -386,7 +405,7 @@ func SetSignatureType(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the from port as a string.
|
// return the from port as a string.
|
||||||
func (c *Client) from() string {
|
func (c *Client) from() string {
|
||||||
if c.fromport == "FROM_PORT=0" {
|
if c.fromport == "FROM_PORT=0" {
|
||||||
return ""
|
return ""
|
||||||
@@ -400,7 +419,7 @@ func (c *Client) from() string {
|
|||||||
return fmt.Sprintf(" FROM_PORT=%v ", c.fromport)
|
return fmt.Sprintf(" FROM_PORT=%v ", c.fromport)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the to port as a string.
|
// return the to port as a string.
|
||||||
func (c *Client) to() string {
|
func (c *Client) to() string {
|
||||||
if c.fromport == "TO_PORT=0" {
|
if c.fromport == "TO_PORT=0" {
|
||||||
return ""
|
return ""
|
||||||
@@ -414,47 +433,47 @@ func (c *Client) to() string {
|
|||||||
return fmt.Sprintf(" TO_PORT=%v ", c.toport)
|
return fmt.Sprintf(" TO_PORT=%v ", c.toport)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the signature type as a string.
|
// return the signature type as a string.
|
||||||
func (c *Client) sigtype() string {
|
func (c *Client) sigtype() string {
|
||||||
return fmt.Sprintf(" %s ", c.sigType)
|
return fmt.Sprintf(" %s ", c.sigType)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the inbound length as a string.
|
// return the inbound length as a string.
|
||||||
func (c *Client) inlength() string {
|
func (c *Client) inlength() string {
|
||||||
return fmt.Sprintf(" inbound.length=%d ", c.inLength)
|
return fmt.Sprintf(" inbound.length=%d ", c.inLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the outbound length as a string.
|
// return the outbound length as a string.
|
||||||
func (c *Client) outlength() string {
|
func (c *Client) outlength() string {
|
||||||
return fmt.Sprintf(" outbound.length=%d ", c.outLength)
|
return fmt.Sprintf(" outbound.length=%d ", c.outLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the inbound length variance as a string.
|
// return the inbound length variance as a string.
|
||||||
func (c *Client) invariance() string {
|
func (c *Client) invariance() string {
|
||||||
return fmt.Sprintf(" inbound.lengthVariance=%d ", c.inVariance)
|
return fmt.Sprintf(" inbound.lengthVariance=%d ", c.inVariance)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the outbound length variance as a string.
|
// return the outbound length variance as a string.
|
||||||
func (c *Client) outvariance() string {
|
func (c *Client) outvariance() string {
|
||||||
return fmt.Sprintf(" outbound.lengthVariance=%d ", c.outVariance)
|
return fmt.Sprintf(" outbound.lengthVariance=%d ", c.outVariance)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the inbound tunnel quantity as a string.
|
// return the inbound tunnel quantity as a string.
|
||||||
func (c *Client) inquantity() string {
|
func (c *Client) inquantity() string {
|
||||||
return fmt.Sprintf(" inbound.quantity=%d ", c.inQuantity)
|
return fmt.Sprintf(" inbound.quantity=%d ", c.inQuantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the outbound tunnel quantity as a string.
|
// return the outbound tunnel quantity as a string.
|
||||||
func (c *Client) outquantity() string {
|
func (c *Client) outquantity() string {
|
||||||
return fmt.Sprintf(" outbound.quantity=%d ", c.outQuantity)
|
return fmt.Sprintf(" outbound.quantity=%d ", c.outQuantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the inbound tunnel quantity as a string.
|
// return the inbound tunnel quantity as a string.
|
||||||
func (c *Client) inbackups() string {
|
func (c *Client) inbackups() string {
|
||||||
return fmt.Sprintf(" inbound.backupQuantity=%d ", c.inQuantity)
|
return fmt.Sprintf(" inbound.backupQuantity=%d ", c.inQuantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the outbound tunnel quantity as a string.
|
// return the outbound tunnel quantity as a string.
|
||||||
func (c *Client) outbackups() string {
|
func (c *Client) outbackups() string {
|
||||||
return fmt.Sprintf(" outbound.backupQuantity=%d ", c.outQuantity)
|
return fmt.Sprintf(" outbound.backupQuantity=%d ", c.outQuantity)
|
||||||
}
|
}
|
||||||
@@ -513,7 +532,7 @@ func (c *Client) compresion() string {
|
|||||||
return " i2cp.gzip=false "
|
return " i2cp.gzip=false "
|
||||||
}
|
}
|
||||||
|
|
||||||
//return all options as string ready for passing to sendcmd
|
// return all options as string ready for passing to sendcmd
|
||||||
func (c *Client) allOptions() string {
|
func (c *Client) allOptions() string {
|
||||||
return c.inlength() +
|
return c.inlength() +
|
||||||
c.outlength() +
|
c.outlength() +
|
||||||
@@ -534,7 +553,7 @@ func (c *Client) allOptions() string {
|
|||||||
c.compresion()
|
c.compresion()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Print return all options as string
|
// Print return all options as string
|
||||||
func (c *Client) Print() string {
|
func (c *Client) Print() string {
|
||||||
return c.inlength() +
|
return c.inlength() +
|
||||||
c.outlength() +
|
c.outlength() +
|
||||||
@@ -554,3 +573,17 @@ func (c *Client) Print() string {
|
|||||||
c.closeidletime() +
|
c.closeidletime() +
|
||||||
c.compresion()
|
c.compresion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) getUser() string {
|
||||||
|
if c.user == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("USER=%s", c.user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getPass() string {
|
||||||
|
if c.pass == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("PASSWORD=%s", c.pass)
|
||||||
|
}
|
||||||
|
@@ -37,7 +37,7 @@ func (c *Client) validCreate() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrString(t *testing.T) {
|
func TestOptionAddrString(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1:7656"), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddr("127.0.0.1:7656"), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func TestOptionAddrString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrStringLh(t *testing.T) {
|
func TestOptionAddrStringLh(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddr("localhost:7656"), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddr("localhost:7656"), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ func TestOptionAddrStringLh(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrSlice(t *testing.T) {
|
func TestOptionAddrSlice(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1", "7656"), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddr("127.0.0.1", "7656"), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ func TestOptionAddrSlice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrMixedSlice(t *testing.T) {
|
func TestOptionAddrMixedSlice(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddrMixed("127.0.0.1", 7656), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddrMixed("127.0.0.1", 7656), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ func TestOptionHost(t *testing.T) {
|
|||||||
SetInBackups(2),
|
SetInBackups(2),
|
||||||
SetOutBackups(2),
|
SetOutBackups(2),
|
||||||
SetEncrypt(true),
|
SetEncrypt(true),
|
||||||
SetDebug(true),
|
SetDebug(false),
|
||||||
SetUnpublished(true),
|
SetUnpublished(true),
|
||||||
SetReduceIdle(true),
|
SetReduceIdle(true),
|
||||||
SetReduceIdleTime(300001),
|
SetReduceIdleTime(300001),
|
||||||
@@ -163,7 +163,7 @@ func TestOptionPortInt(t *testing.T) {
|
|||||||
SetInBackups(2),
|
SetInBackups(2),
|
||||||
SetOutBackups(2),
|
SetOutBackups(2),
|
||||||
SetEncrypt(true),
|
SetEncrypt(true),
|
||||||
SetDebug(true),
|
SetDebug(false),
|
||||||
SetUnpublished(true),
|
SetUnpublished(true),
|
||||||
SetReduceIdle(true),
|
SetReduceIdle(true),
|
||||||
SetReduceIdleTime(300001),
|
SetReduceIdleTime(300001),
|
||||||
|
15
showhider.css
Normal file
15
showhider.css
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/* edgar showhider CSS file */
|
||||||
|
#show {display:none; }
|
||||||
|
#hide {display:block; }
|
||||||
|
#show:target {display: block; }
|
||||||
|
#hide:target {display: none; }
|
||||||
|
|
||||||
|
#shownav {display:none; }
|
||||||
|
#hidenav {display:block; }
|
||||||
|
#shownav:target {display: block; }
|
||||||
|
#hidenav:target {display: none; }
|
||||||
|
|
||||||
|
#donate {display:none; }
|
||||||
|
#hidedonate {display:block; }
|
||||||
|
#donate:target {display: block; }
|
||||||
|
#hidedonate:target {display: none; }
|
165
style.css
Normal file
165
style.css
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/* edgar default CSS file */
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Roboto";
|
||||||
|
font-family: monospace;
|
||||||
|
text-align: justify;
|
||||||
|
background-color: #373636;
|
||||||
|
color: whitesmoke;
|
||||||
|
font-size: 1.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
width: 55%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
width: 55%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-top: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
max-width: 90%;
|
||||||
|
margin-top: 1%;
|
||||||
|
margin-left: 3%;
|
||||||
|
margin-right: 3%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
float: left;
|
||||||
|
top: 5%;
|
||||||
|
left: 5%;
|
||||||
|
max-width: 60%;
|
||||||
|
display: inline;
|
||||||
|
padding-right: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-button:active {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: monospace;
|
||||||
|
border-radius: 5%;
|
||||||
|
padding: 1%;
|
||||||
|
border-color: darkgray;
|
||||||
|
font-size: .9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #C6D9FE;
|
||||||
|
padding: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
color: #C6D9FE;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
background: aliceblue;
|
||||||
|
border-radius: 15%;
|
||||||
|
margin: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 36vw;
|
||||||
|
height: 64vh;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-toolbar a {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: whitesmoke !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#feed {
|
||||||
|
width: 60vw;
|
||||||
|
height: unset !important;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
float: right;
|
||||||
|
background-color: #373636;
|
||||||
|
color: whitesmoke;
|
||||||
|
border: #C6D9FE solid 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-post,
|
||||||
|
.thread {
|
||||||
|
color: whitesmoke !important;
|
||||||
|
background-color: #373636;
|
||||||
|
border: 1px solid darkgray;
|
||||||
|
font-size: inherit;
|
||||||
|
padding-top: 1%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-post {
|
||||||
|
margin-left: 4%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
text-align: center;
|
||||||
|
color: whitesmoke !important;
|
||||||
|
background-color: #373636;
|
||||||
|
border: 1px solid darkgray;
|
||||||
|
font: normal normal normal 14px/1 FontAwesome;
|
||||||
|
font-size: inherit;
|
||||||
|
padding-top: 1%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-hash {
|
||||||
|
text-align: right;
|
||||||
|
color: whitesmoke !important;
|
||||||
|
background-color: #373636;
|
||||||
|
border: 1px solid darkgray;
|
||||||
|
font-size: inherit;
|
||||||
|
padding-top: 1%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-body {
|
||||||
|
text-align: left;
|
||||||
|
color: whitesmoke !important;
|
||||||
|
font-size: inherit;
|
||||||
|
padding-top: 1%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
}
|
||||||
|
#show {display:none; }
|
||||||
|
#hide {display:block; }
|
||||||
|
#show:target {display: block; }
|
||||||
|
#hide:target {display: none; }
|
||||||
|
|
||||||
|
#shownav {display:none; }
|
||||||
|
#hidenav {display:block; }
|
||||||
|
#shownav:target {display: block; }
|
||||||
|
#hidenav:target {display: none; }
|
||||||
|
|
||||||
|
#navbar {
|
||||||
|
float: right;
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
|
#returnhome {
|
||||||
|
font-size: xxx-large;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
display: inline;
|
||||||
|
}
|
Reference in New Issue
Block a user