10 Commits
v0.5 ... v0.5.1

49 changed files with 697 additions and 671 deletions

3
.gitignore vendored
View File

@ -1,5 +1,4 @@
build
release
dist
dispatch
client/dist
client/node_modules

41
.goreleaser.yml Normal file
View File

@ -0,0 +1,41 @@
builds:
- ldflags:
- -s -w -X github.com/khlieng/dispatch/commands.version=v{{.Version}} -X github.com/khlieng/dispatch/commands.commit={{.ShortCommit}} -X github.com/khlieng/dispatch/commands.date={{.Date}}
env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm
- arm64
goarm:
- 6
- 7
archive:
files:
- none*
format_overrides:
- goos: windows
format: zip
checksum:
name_template: "checksums.txt"
changelog:
filters:
exclude:
- "(?i)^update.*dep"
- Merge pull request
- Merge branch
release:
name_template: "{{.Version}}"

View File

@ -1,8 +1,7 @@
language: go
go:
- "1.10.x"
- "1.11.x"
- 1.x
- tip
os:
@ -16,11 +15,11 @@ matrix:
install:
- go get github.com/jteeuwen/go-bindata/...
- cd client
- nvm install 10.11.0
- nvm use 10.11.0
- nvm install 11.2.0
- nvm use 11.2.0
- npm install -g yarn
- yarn global add gulp@next
- yarn --ignore-engines
- yarn
script:
- yarn test:verbose
@ -28,3 +27,11 @@ script:
- cd ..
- go vet ./...
- go test -v -race ./...
deploy:
- provider: script
skip_cleanup: true
script: git checkout -- . && curl -sL https://git.io/goreleaser | bash
on:
tags: true
condition: $TRAVIS_OS_NAME = linux && $TRAVIS_GO_VERSION = 1.*

View File

@ -18,9 +18,9 @@ There is a few different ways of getting it:
### 1. Binary
- **[Windows (x64)](https://github.com/khlieng/dispatch/releases/download/v0.5/dispatch_windows_amd64.zip)**
- **[OS X (x64)](https://github.com/khlieng/dispatch/releases/download/v0.5/dispatch_darwin_amd64.zip)**
- **[Linux (x64)](https://github.com/khlieng/dispatch/releases/download/v0.5/dispatch_linux_amd64.tar.gz)**
- **[Windows (x64)](https://github.com/khlieng/dispatch/releases/download/v0.5.1/dispatch_windows_amd64.zip)**
- **[macOS (x64)](https://github.com/khlieng/dispatch/releases/download/v0.5.1/dispatch_darwin_amd64.zip)**
- **[Linux (x64)](https://github.com/khlieng/dispatch/releases/download/v0.5.1/dispatch_linux_amd64.tar.gz)**
- [Other versions](https://github.com/khlieng/dispatch/releases)
### 2. Go

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,6 @@
/* eslint-disable no-underscore-dangle */
// This entrypoint gets inlined in the index page cached by service workers
// and is responsible for fetching the data we would otherwise embed
window.__env__ = fetch('/data', {
window.__init__ = fetch('/init', {
credentials: 'same-origin'
}).then(res => {
if (res.ok) {

View File

@ -1,8 +1,12 @@
import React from 'react';
import { Provider } from 'react-redux';
import { hot } from 'react-hot-loader';
import { hot, setConfig } from 'react-hot-loader';
import App from 'containers/App';
setConfig({
pureSFC: true
});
const Root = ({ store }) => (
<Provider store={store}>
<App />

View File

@ -239,6 +239,7 @@ export default class MessageBox extends PureComponent {
initialScrollOffset={this.initialScrollTop}
onScroll={this.handleScroll}
className="messagebox-window"
overscanCount={5}
>
{this.renderMessage}
</List>

View File

@ -81,6 +81,7 @@ export default class UserList extends PureComponent {
itemKey={this.getItemKey}
itemSize={this.getItemHeight}
estimatedItemSize={24}
overscanCount={5}
>
{this.renderUser}
</List>

View File

@ -70,11 +70,8 @@ function loadState({ store }, env) {
});
}
export default function initialState(ctx) {
if (window.__env__) {
window.__env__.then(env => loadState(ctx, env));
} else {
const env = JSON.parse(document.getElementById('env').innerHTML);
loadState(ctx, env);
}
export default async function initialState(ctx) {
const env = await window.__init__;
ctx.socket.connect();
loadState(ctx, env);
}

View File

@ -91,16 +91,18 @@ export function compareUsers(a, b) {
export const getChannels = state => state.channels;
export const getSortedChannels = createSelector(getChannels, channels =>
sortBy(
Object.keys(channels).map(server => ({
address: server,
channels: sortBy(Object.keys(channels[server]), channel =>
channel.toLowerCase()
)
})),
server => server.address.toLowerCase()
)
export const getSortedChannels = createSelector(
getChannels,
channels =>
sortBy(
Object.keys(channels).map(server => ({
address: server,
channels: sortBy(Object.keys(channels[server]), channel =>
channel.toLowerCase()
)
})),
server => server.address.toLowerCase()
)
);
export const getSelectedChannel = createSelector(

View File

@ -14,8 +14,6 @@ export default class Socket {
});
this.handlers = [];
this.connected = false;
this.connect();
}
connect() {

View File

@ -46,7 +46,7 @@
"postcss-flexbugs-fixes": "^4.1.0",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.4.0",
"prettier": "1.15.1",
"prettier": "1.15.2",
"react-test-renderer": "^16.7.0-alpha.0",
"style-loader": "^0.23.1",
"terser-webpack-plugin": "^1.1.0",
@ -54,6 +54,7 @@
"webpack": "^4.25.1",
"webpack-dev-middleware": "^3.4.0",
"webpack-hot-middleware": "^2.24.3",
"webpack-plugin-hash-output": "^3.1.0",
"workbox-webpack-plugin": "^3.6.3"
},
"dependencies": {
@ -69,7 +70,7 @@
"lodash": "^4.17.11",
"react": "^16.7.0-alpha.0",
"react-dom": "^16.7.0-alpha.0",
"react-hot-loader": "^4.3.11",
"react-hot-loader": "^4.4.0",
"react-redux": "^6.0.0-beta.2",
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.2.2",
@ -79,8 +80,8 @@
"url-pattern": "^1.0.3"
},
"scripts": {
"prettier": "prettier --write {.*,*.js,src/css/*.css,src/**/*.test.js}",
"prettier:all": "prettier --write {.*,*.js,src/**/*.js,src/css/*.css}",
"prettier": "prettier --write {.*,*.js,css/*.css,**/*.test.js}",
"prettier:all": "prettier --write {.*,*.js,**/*.js,css/*.css}",
"test": "jest",
"test:verbose": "jest --verbose",
"test:watch": "jest --watch",

View File

@ -4,6 +4,7 @@ var postcssPresetEnv = require('postcss-preset-env');
var cssnano = require('cssnano');
var TerserPlugin = require('terser-webpack-plugin');
var { InjectManifest } = require('workbox-webpack-plugin');
var HashOutputPlugin = require('webpack-plugin-hash-output');
module.exports = {
mode: 'production',
@ -12,8 +13,8 @@ module.exports = {
boot: './js/boot'
},
output: {
filename: '[name].[chunkhash:8].js',
chunkFilename: '[name].[chunkhash:8].js',
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js',
publicPath: '/'
},
resolve: {
@ -75,8 +76,8 @@ module.exports = {
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].css',
chunkFilename: '[name].[contenthash:8].css'
filename: '[name].[contenthash].css',
chunkFilename: '[name].[contenthash].css'
}),
new InjectManifest({
swSrc: './js/sw.js',
@ -89,10 +90,19 @@ module.exports = {
/^boot.*\.js$/,
/^runtime.*\.js$/
]
})
}),
new HashOutputPlugin()
],
optimization: {
minimizer: [new TerserPlugin()],
minimizer: [
new TerserPlugin({
terserOptions: {
safari10: true
},
cache: true,
parallel: true
})
],
splitChunks: {
chunks: 'all',
cacheGroups: {

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,12 @@ import (
"github.com/spf13/viper"
)
var (
version = "dev"
commit = "none"
date = "unknown"
)
const logo = `
____ _ _ _
| _ \ (_) ___ _ __ __ _ | |_ ___ | |__
@ -24,7 +30,11 @@ const logo = `
| |_| || |\__ \| |_) || (_| || |_| (__ | | | |
|____/ |_||___/| .__/ \__,_| \__|\___||_| |_|
|_|
v0.5
%s
Commit: %s
Build Date: %s
`
var rootCmd = &cobra.Command{
@ -32,7 +42,7 @@ var rootCmd = &cobra.Command{
Short: "Web-based IRC client in Go.",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if cmd.Use == "dispatch" {
fmt.Println(logo)
fmt.Printf(logo, version, commit, date)
}
storage.Initialize(viper.GetString("dir"))

13
go.mod
View File

@ -38,21 +38,22 @@ require (
github.com/philhofer/fwd v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446 // indirect
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
github.com/spf13/cast v1.3.0
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3 // indirect
github.com/spf13/viper v1.2.1
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect
github.com/stretchr/testify v1.2.2
github.com/syndtr/goleveldb v0.0.0-20181102132633-a4119e27a65d // indirect
github.com/syndtr/goleveldb v0.0.0-20181105012736-f9080354173f // indirect
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect
github.com/tinylib/msgp v0.0.0-20180215042507-3b5c87ab5fb0 // indirect
github.com/willf/bitset v1.1.9 // indirect
github.com/xenolf/lego v1.1.0
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 // indirect
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc
golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc // indirect
github.com/xenolf/lego v1.2.1
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 // indirect
golang.org/x/net v0.0.0-20181113165502-88d92db4c548
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/square/go-jose.v2 v2.1.9 // indirect
)

26
go.sum
View File

@ -93,8 +93,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446 h1:/NRJ5vAYo
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo=
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
@ -115,27 +115,29 @@ github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 h1:JNEGSiWg6D3lcBC
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/syndtr/goleveldb v0.0.0-20181102132633-a4119e27a65d h1:wnS/zl2nFbhU9r6hlfqYEy9qJ0gG89VJGigG6dq7+Eo=
github.com/syndtr/goleveldb v0.0.0-20181102132633-a4119e27a65d/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181105012736-f9080354173f h1:EEVjSRihF8NIbfyCcErpSpNHEKrY3s8EAwqiPENZZn8=
github.com/syndtr/goleveldb v0.0.0-20181105012736-f9080354173f/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0=
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/tinylib/msgp v0.0.0-20180215042507-3b5c87ab5fb0 h1:uAwzi+JwkDdOtQZVqPYljFvJr7i43ZgUYXKypk9Eibk=
github.com/tinylib/msgp v0.0.0-20180215042507-3b5c87ab5fb0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/willf/bitset v1.1.9 h1:GBtFynGY9ZWZmEC9sWuu41/7VBXPFCOAbCbqTflOg9c=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xenolf/lego v1.1.0 h1:Ias1pE9hO98/fI23RLza0T3461YiM720d96oxTRPyuM=
github.com/xenolf/lego v1.1.0/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
github.com/xenolf/lego v1.2.1 h1:wAsBCIaTDlgYbR/yVuP0gzcnZrA94NVc84K6vfOIyyA=
github.com/xenolf/lego v1.2.1/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc h1:ZMCWScCvS2fUVFw8LOpxyUUW5qiviqr4Dg5NdjLeiLU=
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181113165502-88d92db4c548 h1:lqFnrcY5rM6XXZ41MVa5mTlOBrBYultJDG1orIvlqPA=
golang.org/x/net v0.0.0-20181113165502-88d92db4c548/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc h1:SdCq5U4J+PpbSDIl9bM0V1e1Ug1jsnBkAFvTs1htn7U=
golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

9
install.sh Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
Import="github.com/khlieng/dispatch/commands"
Version=$(git describe --tags)
Commit=$(git rev-parse --short HEAD)
Date=$(date +'%Y-%m-%dT%TZ')
go install -ldflags "-s -w -X $Import.version=$Version -X $Import.commit=$Commit -X $Import.date=$Date"

View File

@ -1,33 +1,30 @@
<%! data *indexData, cssPath string, inlineScript string, scripts []string, sw bool %>
<%% import "github.com/mailru/easyjson" %%>
<%! cssPath string, inlineScript string, scripts []string %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#f0f0f0" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#f0f0f0">
<title>Dispatch</title>
<meta name="description" content="Web-based IRC client.">
<% if sw { %>
<link rel="preload" href="/data" as="fetch" crossorigin="anonymous" />
<% } %>
<link rel="preload" href="/init" as="fetch" crossorigin>
<script>
<%== inlineScript %>
</script>
<link rel="preload" href="/font/fontello.woff2?48901973" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="/font/RobotoMono-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="/font/Montserrat-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="/font/Montserrat-Bold.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="/font/RobotoMono-Bold.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
<link rel="preload" href="/font/fontello.woff2?48901973" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/font/RobotoMono-Regular.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/font/Montserrat-Regular.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/font/Montserrat-Bold.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/font/RobotoMono-Bold.woff2" as="font" type="font/woff2" crossorigin>
<% if cssPath != "" { %>
<link href="<%== cssPath %>" rel="stylesheet" />
<link href="<%== cssPath %>" rel="stylesheet">
<% } %>
<link rel="manifest" href="/manifest.json">
@ -36,13 +33,11 @@
<body>
<div id="root"></div>
<% if data != nil { %>
<script id="env" type="application/json"><% easyjson.MarshalToWriter(data, w) %></script>
<% } %>
<% for _, script := range scripts { %>
<script src="<%== script %>"></script>
<% } %>
<noscript>This page needs JavaScript enabled to function.</noscript>
</body>
</html>

View File

@ -4,33 +4,23 @@
package server
import (
"io"
"github.com/mailru/easyjson"
)
func IndexTemplate(w io.Writer, data *indexData, cssPath string, inlineScript string, scripts []string, sw bool) error {
io.WriteString(w, "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /><meta name=\"theme-color\" content=\"#f0f0f0\" /><title>Dispatch</title>")
if sw {
io.WriteString(w, "<link rel=\"preload\" href=\"/data\" as=\"fetch\" crossorigin=\"anonymous\" />")
}
io.WriteString(w, "<script>")
func IndexTemplate(w io.Writer, cssPath string, inlineScript string, scripts []string) error {
io.WriteString(w, "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta name=\"theme-color\" content=\"#f0f0f0\"><title>Dispatch</title><meta name=\"description\" content=\"Web-based IRC client.\"><link rel=\"preload\" href=\"/init\" as=\"fetch\" crossorigin><script>")
io.WriteString(w, inlineScript )
io.WriteString(w, "</script><link rel=\"preload\" href=\"/font/fontello.woff2?48901973\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\" /><link rel=\"preload\" href=\"/font/RobotoMono-Regular.woff2\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\" /><link rel=\"preload\" href=\"/font/Montserrat-Regular.woff2\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\" /><link rel=\"preload\" href=\"/font/Montserrat-Bold.woff2\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\" /><link rel=\"preload\" href=\"/font/RobotoMono-Bold.woff2\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\" />")
io.WriteString(w, "</script><link rel=\"preload\" href=\"/font/fontello.woff2?48901973\" as=\"font\" type=\"font/woff2\" crossorigin><link rel=\"preload\" href=\"/font/RobotoMono-Regular.woff2\" as=\"font\" type=\"font/woff2\" crossorigin><link rel=\"preload\" href=\"/font/Montserrat-Regular.woff2\" as=\"font\" type=\"font/woff2\" crossorigin><link rel=\"preload\" href=\"/font/Montserrat-Bold.woff2\" as=\"font\" type=\"font/woff2\" crossorigin><link rel=\"preload\" href=\"/font/RobotoMono-Bold.woff2\" as=\"font\" type=\"font/woff2\" crossorigin>")
if cssPath != "" {
io.WriteString(w, "<link href=\"")
io.WriteString(w, cssPath )
io.WriteString(w, "\" rel=\"stylesheet\" />")
io.WriteString(w, "\" rel=\"stylesheet\">")
}
io.WriteString(w, "<link rel=\"manifest\" href=\"/manifest.json\"></head><body><div id=\"root\"></div>")
if data != nil {
io.WriteString(w, "<script id=\"env\" type=\"application/json\">")
easyjson.MarshalToWriter(data, w)
io.WriteString(w, "</script>")
}
for _, script := range scripts {
io.WriteString(w, "<script src=\"")
io.WriteString(w, script )
io.WriteString(w, "\"></script>")
}
io.WriteString(w, "</body></html>")
io.WriteString(w, "<noscript>This page needs JavaScript enabled to function.</noscript></body></html>")
return nil
}

View File

@ -47,13 +47,11 @@ func newH2PushAsset(name string) h2PushAsset {
var (
files []*File
indexStylesheet string
indexScripts []string
inlineScript string
inlineScriptSha256 string
inlineScriptSW string
inlineScriptSWSha256 string
serviceWorker []byte
indexStylesheet string
indexScripts []string
inlineScript string
inlineScriptSha256 string
serviceWorker []byte
h2PushAssets []h2PushAsset
h2PushCookieValue string
@ -69,6 +67,8 @@ var (
".json": "application/json",
}
robots = []byte("User-agent: *\nDisallow: /")
hstsHeader string
cspEnabled bool
)
@ -80,17 +80,12 @@ func (d *Dispatch) initFileServer() {
bootloader := decompressedAsset(findAssetName("boot*.js"))
runtime := decompressedAsset(findAssetName("runtime*.js"))
inlineScript = string(runtime)
inlineScriptSW = string(bootloader) + string(runtime)
inlineScript = string(bootloader) + string(runtime)
hash := sha256.New()
hash.Write(runtime)
inlineScriptSha256 = base64.StdEncoding.EncodeToString(hash.Sum(nil))
hash.Reset()
hash.Write(bootloader)
hash.Write(runtime)
inlineScriptSWSha256 = base64.StdEncoding.EncodeToString(hash.Sum(nil))
inlineScriptSha256 = base64.StdEncoding.EncodeToString(hash.Sum(nil))
indexStylesheet = findAssetName("main*.css")
indexScripts = []string{
@ -146,15 +141,15 @@ func (d *Dispatch) initFileServer() {
serviceWorker = decompressedAsset("sw.js")
hash.Reset()
IndexTemplate(hash, nil, indexStylesheet, inlineScriptSW, indexScripts, true)
IndexTemplate(hash, indexStylesheet, inlineScript, indexScripts)
indexHash := base64.StdEncoding.EncodeToString(hash.Sum(nil))
serviceWorker = append(serviceWorker, []byte(`
workbox.precaching.precacheAndRoute([{
revision: '`+indexHash+`',
url: '/?sw'
url: '/'
}]);
workbox.routing.registerNavigationRoute('/?sw');`)...)
workbox.routing.registerNavigationRoute('/');`)...)
if viper.GetBool("https.hsts.enabled") && viper.GetBool("https.enabled") {
hstsHeader = "max-age=" + viper.GetString("https.hsts.max_age")
@ -232,6 +227,13 @@ func (d *Dispatch) serveFiles(w http.ResponseWriter, r *http.Request) {
return
}
if r.URL.Path == "/robots.txt" {
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Content-Length", strconv.Itoa(len(robots)))
w.Write(robots)
return
}
for _, file := range files {
if strings.HasSuffix(r.URL.Path, file.Path) {
d.serveFile(w, r, file)
@ -274,8 +276,6 @@ func (d *Dispatch) serveIndex(w http.ResponseWriter, r *http.Request) {
}
}
_, sw := r.URL.Query()["sw"]
if cspEnabled {
var wsSrc string
if r.TLS != nil {
@ -284,12 +284,18 @@ func (d *Dispatch) serveIndex(w http.ResponseWriter, r *http.Request) {
wsSrc = "ws://" + r.Host
}
inlineSha := inlineScriptSha256
if sw {
inlineSha = inlineScriptSWSha256
csp := []string{
"default-src 'none'",
"script-src 'self' 'sha256-" + inlineScriptSha256 + "'",
"style-src 'self' 'unsafe-inline'",
"font-src 'self'",
"img-src 'self'",
"manifest-src 'self'",
"connect-src 'self' " + wsSrc,
"worker-src 'self'",
}
w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self' 'sha256-"+inlineSha+"'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self'; manifest-src 'self'; connect-src 'self' "+wsSrc)
w.Header().Set("Content-Security-Policy", strings.Join(csp, "; "))
}
w.Header().Set("Content-Type", "text/html")
@ -303,21 +309,14 @@ func (d *Dispatch) serveIndex(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Strict-Transport-Security", hstsHeader)
}
var data *indexData
inline := inlineScriptSW
if !sw {
data = getIndexData(r, r.URL.EscapedPath(), d.handleAuth(w, r, false, true))
inline = inlineScript
}
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
gzw := getGzipWriter(w)
IndexTemplate(gzw, data, indexStylesheet, inline, indexScripts, sw)
IndexTemplate(gzw, indexStylesheet, inlineScript, indexScripts)
putGzipWriter(gzw)
} else {
IndexTemplate(w, data, indexStylesheet, inline, indexScripts, sw)
IndexTemplate(w, indexStylesheet, inlineScript, indexScripts)
}
}

View File

@ -172,7 +172,7 @@ func (d *Dispatch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
state := d.handleAuth(w, r, true, true)
state := d.handleAuth(w, r, false, false)
if state == nil {
log.Println("[Auth] No state")
fail(w, http.StatusInternalServerError)
@ -180,8 +180,8 @@ func (d *Dispatch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
d.upgradeWS(w, r, state)
} else if strings.HasPrefix(r.URL.Path, "/data") {
state := d.handleAuth(w, r, false, false)
} else if strings.HasPrefix(r.URL.Path, "/init") {
state := d.handleAuth(w, r, true, true)
data := getIndexData(r, "/", state)
writeJSON(w, r, data)

View File

@ -665,7 +665,7 @@ func (c *Client) getAuthzForOrder(order orderResource) ([]authorization, error)
go func(authzURL string) {
var authz authorization
_, err := getJSON(authzURL, &authz)
_, err := postAsGet(c.jws, authzURL, &authz)
if err != nil {
errc <- domainError{Domain: authz.Identifier.Value, Error: err}
return
@ -789,7 +789,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
case <-stopTimer.C:
return nil, errors.New("certificate polling timed out")
case <-retryTick.C:
_, err := getJSON(order.URL, &retOrder)
_, err := postAsGet(c.jws, order.URL, &retOrder)
if err != nil {
return nil, err
}
@ -813,7 +813,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResource, bundle bool) (bool, error) {
switch order.Status {
case statusValid:
resp, err := httpGet(order.Certificate)
resp, err := postAsGet(c.jws, order.Certificate, nil)
if err != nil {
return false, err
}
@ -871,7 +871,7 @@ func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResou
// getIssuerCertificate requests the issuer certificate
func (c *Client) getIssuerCertificate(url string) ([]byte, error) {
log.Infof("acme: Requesting issuer cert from %s", url)
resp, err := httpGet(url)
resp, err := postAsGet(c.jws, url, nil)
if err != nil {
return nil, err
}
@ -914,7 +914,10 @@ func parseLinks(links []string) map[string]string {
func validate(j *jws, domain, uri string, c challenge) error {
var chlng challenge
hdr, err := postJSON(j, uri, c, &chlng)
// Challenge initiation is done by sending a JWS payload containing the
// trivial JSON object `{}`. We use an empty struct instance as the postJSON
// payload here to achieve this result.
hdr, err := postJSON(j, uri, struct{}{}, &chlng)
if err != nil {
return err
}
@ -940,11 +943,15 @@ func validate(j *jws, domain, uri string, c challenge) error {
// If it doesn't, we'll just poll hard.
ra = 5
}
time.Sleep(time.Duration(ra) * time.Second)
hdr, err = getJSON(uri, &chlng)
resp, err := postAsGet(j, uri, &chlng)
if err != nil {
return err
}
if resp != nil {
hdr = resp.Header
}
}
}

View File

@ -151,48 +151,56 @@ func postJSON(j *jws, uri string, reqBody, respBody interface{}) (http.Header, e
return nil, errors.New("failed to marshal network message")
}
resp, err := j.post(uri, jsonBytes)
if err != nil {
return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
resp, err := post(j, uri, jsonBytes, respBody)
if resp == nil {
return nil, err
}
defer resp.Body.Close()
return resp.Header, err
}
func postAsGet(j *jws, uri string, respBody interface{}) (*http.Response, error) {
return post(j, uri, []byte{}, respBody)
}
func post(j *jws, uri string, reqBody []byte, respBody interface{}) (*http.Response, error) {
resp, err := j.post(uri, reqBody)
if err != nil {
return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
}
if resp.StatusCode >= http.StatusBadRequest {
err = handleHTTPError(resp)
switch err.(type) {
case NonceError:
// Retry once if the nonce was invalidated
retryResp, errP := j.post(uri, jsonBytes)
retryResp, errP := j.post(uri, reqBody)
if errP != nil {
return nil, fmt.Errorf("failed to post JWS message. -> %v", errP)
}
defer retryResp.Body.Close()
if retryResp.StatusCode >= http.StatusBadRequest {
return retryResp.Header, handleHTTPError(retryResp)
return retryResp, handleHTTPError(retryResp)
}
if respBody == nil {
return retryResp.Header, nil
return retryResp, nil
}
return retryResp.Header, json.NewDecoder(retryResp.Body).Decode(respBody)
return retryResp, json.NewDecoder(retryResp.Body).Decode(respBody)
default:
return resp.Header, err
return resp, err
}
}
if respBody == nil {
return resp.Header, nil
return resp, nil
}
return resp.Header, json.NewDecoder(resp.Body).Decode(respBody)
return resp, json.NewDecoder(resp.Body).Decode(respBody)
}
// userAgent builds and returns the User-Agent string to use in requests.

View File

@ -12,8 +12,8 @@ import (
)
// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension.
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-5.1
var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-5.1
var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
type tlsALPNChallenge struct {
jws *jws
@ -58,7 +58,7 @@ func TLSALPNChallengeBlocks(domain, keyAuth string) ([]byte, []byte, error) {
// Add the keyAuth digest as the acmeValidation-v1 extension
// (marked as critical such that it won't be used by non-ACME software).
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-3
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-3
extensions := []pkix.Extension{
{
Id: idPeAcmeIdentifierV1,

View File

@ -121,18 +121,21 @@ var zoneCache = ipv6ZoneCache{
toName: make(map[int]string),
}
func (zc *ipv6ZoneCache) update(ift []net.Interface) {
// update refreshes the network interface information if the cache was last
// updated more than 1 minute ago, or if force is set. It returns whether the
// cache was updated.
func (zc *ipv6ZoneCache) update(ift []net.Interface, force bool) (updated bool) {
zc.Lock()
defer zc.Unlock()
now := time.Now()
if zc.lastFetched.After(now.Add(-60 * time.Second)) {
return
if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
return false
}
zc.lastFetched = now
if len(ift) == 0 {
var err error
if ift, err = net.Interfaces(); err != nil {
return
return false
}
}
zc.toIndex = make(map[string]int, len(ift))
@ -143,25 +146,38 @@ func (zc *ipv6ZoneCache) update(ift []net.Interface) {
zc.toName[ifi.Index] = ifi.Name
}
}
return true
}
func (zc *ipv6ZoneCache) name(zone int) string {
zoneCache.update(nil)
updated := zoneCache.update(nil, false)
zoneCache.RLock()
defer zoneCache.RUnlock()
name, ok := zoneCache.toName[zone]
if !ok {
zoneCache.RUnlock()
if !ok && !updated {
zoneCache.update(nil, true)
zoneCache.RLock()
name, ok = zoneCache.toName[zone]
zoneCache.RUnlock()
}
if !ok { // last resort
name = strconv.Itoa(zone)
}
return name
}
func (zc *ipv6ZoneCache) index(zone string) int {
zoneCache.update(nil)
updated := zoneCache.update(nil, false)
zoneCache.RLock()
defer zoneCache.RUnlock()
index, ok := zoneCache.toIndex[zone]
if !ok {
zoneCache.RUnlock()
if !ok && !updated {
zoneCache.update(nil, true)
zoneCache.RLock()
index, ok = zoneCache.toIndex[zone]
zoneCache.RUnlock()
}
if !ok { // last resort
index, _ = strconv.Atoi(zone)
}
return index

View File

@ -241,4 +241,5 @@
// IncludeSourceSpecificGroup may return an error.
package ipv4 // import "golang.org/x/net/ipv4"
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.
// BUG(mikio): This package is not implemented on AIX, JS, NaCl and
// Plan 9.

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js,!nacl,!plan9,!windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv4

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build !go1.9
// +build !js,!nacl,!plan9,!windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv4

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build go1.9
// +build !js,!nacl,!plan9,!windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv4

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js nacl plan9 windows
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
package ipv4

View File

@ -240,4 +240,5 @@
// IncludeSourceSpecificGroup may return an error.
package ipv6 // import "golang.org/x/net/ipv6"
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.
// BUG(mikio): This package is not implemented on AIX, JS, NaCl and
// Plan 9.

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js,!nacl,!plan9,!windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build !go1.9
// +build !js,!nacl,!plan9,!windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build go1.9
// +build !js,!nacl,!plan9,!windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package ipv6

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js nacl plan9 windows
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
package ipv6

View File

@ -15,12 +15,6 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R3
@ -36,12 +30,6 @@ TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4

View File

@ -101,7 +101,7 @@ includes_DragonFly='
'
includes_FreeBSD='
#include <sys/capability.h>
#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/event.h>

View File

@ -65,6 +65,10 @@ func main() {
convertUtsnameRegex := regexp.MustCompile(`((Sys|Node|Domain)name|Release|Version|Machine)(\s+)\[(\d+)\]u?int8`)
b = convertUtsnameRegex.ReplaceAll(b, []byte("$1$3[$4]byte"))
// Convert [1024]int8 to [1024]byte in Ptmget members
convertPtmget := regexp.MustCompile(`([SC]n)(\s+)\[(\d+)\]u?int8`)
b = convertPtmget.ReplaceAll(b, []byte("$1[$3]byte"))
// Remove spare fields (e.g. in Statx_t)
spareFieldsRegex := regexp.MustCompile(`X__spare\S*`)
b = spareFieldsRegex.ReplaceAll(b, []byte("_"))

View File

@ -13,6 +13,7 @@
package unix
import (
"runtime"
"syscall"
"unsafe"
)
@ -190,6 +191,13 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
return &value, err
}
func IoctlGetPtmget(fd int, req uint) (*Ptmget, error) {
var value Ptmget
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
runtime.KeepAlive(value)
return &value, err
}
func Uname(uname *Utsname) error {
mib := []_C_int{CTL_KERN, KERN_OSTYPE}
n := unsafe.Sizeof(uname.Sysname)

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// +build !gccgo
// +build !gccgo,!ppc64le,!ppc64
package unix

24
vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// +build ppc64le ppc64
// +build !gccgo
package unix
import "syscall"
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
return syscall.Syscall(trap, a1, a2, a3)
}
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
return syscall.Syscall6(trap, a1, a2, a3, a4, a5, a6)
}
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
return syscall.RawSyscall(trap, a1, a2, a3)
}
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
return syscall.RawSyscall6(trap, a1, a2, a3, a4, a5, a6)
}

View File

@ -26,7 +26,7 @@ package unix
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/capability.h>
#include <sys/capsicum.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/mount.h>

View File

@ -248,6 +248,8 @@ type Termios C.struct_termios
type Winsize C.struct_winsize
type Ptmget C.struct_ptmget
// fchmodat-like syscalls.
const (

View File

@ -402,6 +402,13 @@ type Winsize struct {
Ypixel uint16
}
type Ptmget struct {
Cfd int32
Sfd int32
Cn [1024]byte
Sn [1024]byte
}
const (
AT_FDCWD = -0x64
AT_SYMLINK_NOFOLLOW = 0x200

View File

@ -409,6 +409,13 @@ type Winsize struct {
Ypixel uint16
}
type Ptmget struct {
Cfd int32
Sfd int32
Cn [1024]byte
Sn [1024]byte
}
const (
AT_FDCWD = -0x64
AT_SYMLINK_NOFOLLOW = 0x200

View File

@ -407,6 +407,13 @@ type Winsize struct {
Ypixel uint16
}
type Ptmget struct {
Cfd int32
Sfd int32
Cn [1024]byte
Sn [1024]byte
}
const (
AT_FDCWD = -0x64
AT_SYMLINK_NOFOLLOW = 0x200

8
vendor/modules.txt vendored
View File

@ -127,15 +127,15 @@ github.com/stretchr/testify/assert
github.com/tinylib/msgp/msgp
# github.com/willf/bitset v1.1.9
github.com/willf/bitset
# github.com/xenolf/lego v1.1.0
# github.com/xenolf/lego v1.2.1
github.com/xenolf/lego/acme
github.com/xenolf/lego/log
# golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16
# golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869
golang.org/x/crypto/ocsp
golang.org/x/crypto/ed25519
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/ed25519/internal/edwards25519
# golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc
# golang.org/x/net v0.0.0-20181113165502-88d92db4c548
golang.org/x/net/html
golang.org/x/net/html/atom
golang.org/x/net/ipv4
@ -143,7 +143,7 @@ golang.org/x/net/ipv6
golang.org/x/net/bpf
golang.org/x/net/internal/iana
golang.org/x/net/internal/socket
# golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc
# golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8
golang.org/x/sys/unix
# golang.org/x/text v0.3.0
golang.org/x/text/transform