Browse Source

fix #782 (bring vendor into the main tree)

tags/v2.0.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
d0aa7cc860
100 changed files with 17471 additions and 31 deletions
  1. 0
    3
      .gitmodules
  2. 1
    20
      DEVELOPING.md
  3. 4
    7
      Makefile
  4. 0
    1
      vendor
  5. 201
    0
      vendor/code.cloudfoundry.org/bytefmt/LICENSE
  6. 20
    0
      vendor/code.cloudfoundry.org/bytefmt/NOTICE
  7. 15
    0
      vendor/code.cloudfoundry.org/bytefmt/README.md
  8. 121
    0
      vendor/code.cloudfoundry.org/bytefmt/bytes.go
  9. 1
    0
      vendor/code.cloudfoundry.org/bytefmt/package.go
  10. 25
    0
      vendor/github.com/docopt/docopt-go/.gitignore
  11. 32
    0
      vendor/github.com/docopt/docopt-go/.travis.yml
  12. 21
    0
      vendor/github.com/docopt/docopt-go/LICENSE
  13. 116
    0
      vendor/github.com/docopt/docopt-go/README.md
  14. 49
    0
      vendor/github.com/docopt/docopt-go/doc.go
  15. 575
    0
      vendor/github.com/docopt/docopt-go/docopt.go
  16. 49
    0
      vendor/github.com/docopt/docopt-go/error.go
  17. 264
    0
      vendor/github.com/docopt/docopt-go/opts.go
  18. 550
    0
      vendor/github.com/docopt/docopt-go/pattern.go
  19. 9
    0
      vendor/github.com/docopt/docopt-go/test_golang.docopt
  20. 957
    0
      vendor/github.com/docopt/docopt-go/testcases.docopt
  21. 126
    0
      vendor/github.com/docopt/docopt-go/token.go
  22. 38
    0
      vendor/github.com/go-asn1-ber/asn1-ber/.travis.yml
  23. 22
    0
      vendor/github.com/go-asn1-ber/asn1-ber/LICENSE
  24. 24
    0
      vendor/github.com/go-asn1-ber/asn1-ber/README.md
  25. 512
    0
      vendor/github.com/go-asn1-ber/asn1-ber/ber.go
  26. 25
    0
      vendor/github.com/go-asn1-ber/asn1-ber/content_int.go
  27. 3
    0
      vendor/github.com/go-asn1-ber/asn1-ber/go.mod
  28. 35
    0
      vendor/github.com/go-asn1-ber/asn1-ber/header.go
  29. 112
    0
      vendor/github.com/go-asn1-ber/asn1-ber/identifier.go
  30. 81
    0
      vendor/github.com/go-asn1-ber/asn1-ber/length.go
  31. 24
    0
      vendor/github.com/go-asn1-ber/asn1-ber/util.go
  32. 22
    0
      vendor/github.com/go-ldap/ldap/v3/LICENSE
  33. 91
    0
      vendor/github.com/go-ldap/ldap/v3/add.go
  34. 152
    0
      vendor/github.com/go-ldap/ldap/v3/bind.go
  35. 30
    0
      vendor/github.com/go-ldap/ldap/v3/client.go
  36. 61
    0
      vendor/github.com/go-ldap/ldap/v3/compare.go
  37. 565
    0
      vendor/github.com/go-ldap/ldap/v3/conn.go
  38. 499
    0
      vendor/github.com/go-ldap/ldap/v3/control.go
  39. 30
    0
      vendor/github.com/go-ldap/ldap/v3/debug.go
  40. 59
    0
      vendor/github.com/go-ldap/ldap/v3/del.go
  41. 207
    0
      vendor/github.com/go-ldap/ldap/v3/dn.go
  42. 4
    0
      vendor/github.com/go-ldap/ldap/v3/doc.go
  43. 236
    0
      vendor/github.com/go-ldap/ldap/v3/error.go
  44. 487
    0
      vendor/github.com/go-ldap/ldap/v3/filter.go
  45. 5
    0
      vendor/github.com/go-ldap/ldap/v3/go.mod
  46. 2
    0
      vendor/github.com/go-ldap/ldap/v3/go.sum
  47. 340
    0
      vendor/github.com/go-ldap/ldap/v3/ldap.go
  48. 75
    0
      vendor/github.com/go-ldap/ldap/v3/moddn.go
  49. 132
    0
      vendor/github.com/go-ldap/ldap/v3/modify.go
  50. 126
    0
      vendor/github.com/go-ldap/ldap/v3/passwdmodify.go
  51. 66
    0
      vendor/github.com/go-ldap/ldap/v3/request.go
  52. 370
    0
      vendor/github.com/go-ldap/ldap/v3/search.go
  53. 19
    0
      vendor/github.com/goshuirc/e-nfa/.travis.yml
  54. 122
    0
      vendor/github.com/goshuirc/e-nfa/README.md
  55. 185
    0
      vendor/github.com/goshuirc/e-nfa/enfa.go
  56. 13
    0
      vendor/github.com/goshuirc/irc-go/LICENSE
  57. 86
    0
      vendor/github.com/goshuirc/irc-go/ircfmt/doc.go
  58. 330
    0
      vendor/github.com/goshuirc/irc-go/ircfmt/ircfmt.go
  59. 7
    0
      vendor/github.com/goshuirc/irc-go/ircmatch/doc.go
  60. 57
    0
      vendor/github.com/goshuirc/irc-go/ircmatch/ircmatch.go
  61. 7
    0
      vendor/github.com/goshuirc/irc-go/ircmsg/doc.go
  62. 401
    0
      vendor/github.com/goshuirc/irc-go/ircmsg/message.go
  63. 75
    0
      vendor/github.com/goshuirc/irc-go/ircmsg/tags.go
  64. 9
    0
      vendor/github.com/mattn/go-colorable/.travis.yml
  65. 21
    0
      vendor/github.com/mattn/go-colorable/LICENSE
  66. 48
    0
      vendor/github.com/mattn/go-colorable/README.md
  67. 29
    0
      vendor/github.com/mattn/go-colorable/colorable_appengine.go
  68. 30
    0
      vendor/github.com/mattn/go-colorable/colorable_others.go
  69. 1005
    0
      vendor/github.com/mattn/go-colorable/colorable_windows.go
  70. 3
    0
      vendor/github.com/mattn/go-colorable/go.mod
  71. 4
    0
      vendor/github.com/mattn/go-colorable/go.sum
  72. 55
    0
      vendor/github.com/mattn/go-colorable/noncolorable.go
  73. 13
    0
      vendor/github.com/mattn/go-isatty/.travis.yml
  74. 9
    0
      vendor/github.com/mattn/go-isatty/LICENSE
  75. 50
    0
      vendor/github.com/mattn/go-isatty/README.md
  76. 2
    0
      vendor/github.com/mattn/go-isatty/doc.go
  77. 5
    0
      vendor/github.com/mattn/go-isatty/go.mod
  78. 4
    0
      vendor/github.com/mattn/go-isatty/go.sum
  79. 23
    0
      vendor/github.com/mattn/go-isatty/isatty_android.go
  80. 24
    0
      vendor/github.com/mattn/go-isatty/isatty_bsd.go
  81. 15
    0
      vendor/github.com/mattn/go-isatty/isatty_others.go
  82. 22
    0
      vendor/github.com/mattn/go-isatty/isatty_plan9.go
  83. 22
    0
      vendor/github.com/mattn/go-isatty/isatty_solaris.go
  84. 19
    0
      vendor/github.com/mattn/go-isatty/isatty_tcgets.go
  85. 125
    0
      vendor/github.com/mattn/go-isatty/isatty_windows.go
  86. 1
    0
      vendor/github.com/mgutz/ansi/.gitignore
  87. 9
    0
      vendor/github.com/mgutz/ansi/LICENSE
  88. 121
    0
      vendor/github.com/mgutz/ansi/README.md
  89. 285
    0
      vendor/github.com/mgutz/ansi/ansi.go
  90. 65
    0
      vendor/github.com/mgutz/ansi/doc.go
  91. 57
    0
      vendor/github.com/mgutz/ansi/print.go
  92. 2
    0
      vendor/github.com/oragono/confusables/.gitignore
  93. 28
    0
      vendor/github.com/oragono/confusables/LICENSE
  94. 17
    0
      vendor/github.com/oragono/confusables/README.md
  95. 82
    0
      vendor/github.com/oragono/confusables/confusables.go
  96. 6317
    0
      vendor/github.com/oragono/confusables/tables.go
  97. 38
    0
      vendor/github.com/oragono/confusables/tweaks.go
  98. 20
    0
      vendor/github.com/oragono/go-ident/LICENSE
  99. 19
    0
      vendor/github.com/oragono/go-ident/README.md
  100. 0
    0
      vendor/github.com/oragono/go-ident/client.go

+ 0
- 3
.gitmodules View File

@@ -1,3 +0,0 @@
1
-[submodule "vendor"]
2
-	path = vendor
3
-	url = https://github.com/oragono/oragono-vendor.git

+ 1
- 20
DEVELOPING.md View File

@@ -7,9 +7,7 @@ This is just a bunch of tips and tricks we keep in mind while developing Oragono
7 7
 
8 8
 You should use the [latest distribution of the Go language for your OS and architecture](https://golang.org/dl/). (If `uname -m` on your Raspberry Pi reports `armv7l`, use the `armv6l` distribution of Go; if it reports v8, you may be able to use the `arm64` distribution.)
9 9
 
10
-Oragono vendors all its dependencies. The vendored code is tracked via a git submodule: `vendor/` is a submodule pointing to the [oragono-vendor](https://github.com/oragono/oragono-vendor) repository. As long as you're not modifying the vendored dependencies, `make` should take care of everything for you --- but if you are, see the "vendor" section below.
11
-
12
-Because of this, Oragono is self-contained and you should not need to fetch any dependencies with `go get`. Doing so is not recommended, since it may fetch incompatible versions of the dependencies. If you're having trouble building the code, it's very likely because your clone of the repository is in the wrong place: Go is very opinionated about where you should keep your code. Take a look at the [go workspaces documentation](https://golang.org/doc/code.html) if you're having trouble.
10
+Oragono vendors all its dependencies. Because of this, Oragono is self-contained and you should not need to fetch any dependencies with `go get`. Doing so is not recommended, since it may fetch incompatible versions of the dependencies.
13 11
 
14 12
 
15 13
 ## Branches
@@ -59,23 +57,6 @@ New release of Oragono!
59 57
 
60 58
 
61 59
 
62
-## Updating `vendor/`
63
-
64
-The `vendor/` directory holds our dependencies. When we import new repos, we need to update this folder to contain these new deps. This is something that I'll mostly be handling.
65
-
66
-To update this folder:
67
-
68
-1. Install https://github.com/golang/dep
69
-2. `cd` to Oragono folder
70
-3. `dep ensure -update`
71
-4. `cd vendor`
72
-5. Commit the changes with the message `"Updated packages"`
73
-6. `cd ..`
74
-4. Commit the result with the message `"vendor: Updated submodules"`
75
-
76
-This will make sure things stay nice and up-to-date for users.
77
-
78
-
79 60
 ## Fuzzing and Testing
80 61
 
81 62
 Fuzzing can be useful. We don't have testing done inside the IRCd itself, but this fuzzer I've written works alright and has helped shake out various bugs: [irc_fuzz.py](https://gist.github.com/DanielOaks/63ae611039cdf591dfa4).

+ 4
- 7
Makefile View File

@@ -1,24 +1,21 @@
1
-.PHONY: all install build release capdefs deps test
1
+.PHONY: all install build release capdefs test
2 2
 
3 3
 capdef_file = ./irc/caps/defs.go
4 4
 
5 5
 all: install
6 6
 
7
-install: deps
7
+install:
8 8
 	go install -v
9 9
 
10
-build: deps
10
+build:
11 11
 	go build -v
12 12
 
13
-release: deps
13
+release:
14 14
 	goreleaser --skip-publish --rm-dist
15 15
 
16 16
 capdefs:
17 17
 	python3 ./gencapdefs.py > ${capdef_file}
18 18
 
19
-deps:
20
-	git submodule update --init
21
-
22 19
 test:
23 20
 	python3 ./gencapdefs.py | diff - ${capdef_file}
24 21
 	cd irc && go test . && go vet .

+ 0
- 1
vendor

@@ -1 +0,0 @@
1
-Subproject commit 6e49b8a260f1ba3351c17876c2e2d0044c315078

+ 201
- 0
vendor/code.cloudfoundry.org/bytefmt/LICENSE View File

@@ -0,0 +1,201 @@
1
+                                 Apache License
2
+                           Version 2.0, January 2004
3
+                        http://www.apache.org/licenses/
4
+
5
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+   1. Definitions.
8
+
9
+      "License" shall mean the terms and conditions for use, reproduction,
10
+      and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+      "Licensor" shall mean the copyright owner or entity authorized by
13
+      the copyright owner that is granting the License.
14
+
15
+      "Legal Entity" shall mean the union of the acting entity and all
16
+      other entities that control, are controlled by, or are under common
17
+      control with that entity. For the purposes of this definition,
18
+      "control" means (i) the power, direct or indirect, to cause the
19
+      direction or management of such entity, whether by contract or
20
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+      outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+      "You" (or "Your") shall mean an individual or Legal Entity
24
+      exercising permissions granted by this License.
25
+
26
+      "Source" form shall mean the preferred form for making modifications,
27
+      including but not limited to software source code, documentation
28
+      source, and configuration files.
29
+
30
+      "Object" form shall mean any form resulting from mechanical
31
+      transformation or translation of a Source form, including but
32
+      not limited to compiled object code, generated documentation,
33
+      and conversions to other media types.
34
+
35
+      "Work" shall mean the work of authorship, whether in Source or
36
+      Object form, made available under the License, as indicated by a
37
+      copyright notice that is included in or attached to the work
38
+      (an example is provided in the Appendix below).
39
+
40
+      "Derivative Works" shall mean any work, whether in Source or Object
41
+      form, that is based on (or derived from) the Work and for which the
42
+      editorial revisions, annotations, elaborations, or other modifications
43
+      represent, as a whole, an original work of authorship. For the purposes
44
+      of this License, Derivative Works shall not include works that remain
45
+      separable from, or merely link (or bind by name) to the interfaces of,
46
+      the Work and Derivative Works thereof.
47
+
48
+      "Contribution" shall mean any work of authorship, including
49
+      the original version of the Work and any modifications or additions
50
+      to that Work or Derivative Works thereof, that is intentionally
51
+      submitted to Licensor for inclusion in the Work by the copyright owner
52
+      or by an individual or Legal Entity authorized to submit on behalf of
53
+      the copyright owner. For the purposes of this definition, "submitted"
54
+      means any form of electronic, verbal, or written communication sent
55
+      to the Licensor or its representatives, including but not limited to
56
+      communication on electronic mailing lists, source code control systems,
57
+      and issue tracking systems that are managed by, or on behalf of, the
58
+      Licensor for the purpose of discussing and improving the Work, but
59
+      excluding communication that is conspicuously marked or otherwise
60
+      designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+      "Contributor" shall mean Licensor and any individual or Legal Entity
63
+      on behalf of whom a Contribution has been received by Licensor and
64
+      subsequently incorporated within the Work.
65
+
66
+   2. Grant of Copyright License. Subject to the terms and conditions of
67
+      this License, each Contributor hereby grants to You a perpetual,
68
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+      copyright license to reproduce, prepare Derivative Works of,
70
+      publicly display, publicly perform, sublicense, and distribute the
71
+      Work and such Derivative Works in Source or Object form.
72
+
73
+   3. Grant of Patent License. Subject to the terms and conditions of
74
+      this License, each Contributor hereby grants to You a perpetual,
75
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+      (except as stated in this section) patent license to make, have made,
77
+      use, offer to sell, sell, import, and otherwise transfer the Work,
78
+      where such license applies only to those patent claims licensable
79
+      by such Contributor that are necessarily infringed by their
80
+      Contribution(s) alone or by combination of their Contribution(s)
81
+      with the Work to which such Contribution(s) was submitted. If You
82
+      institute patent litigation against any entity (including a
83
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+      or a Contribution incorporated within the Work constitutes direct
85
+      or contributory patent infringement, then any patent licenses
86
+      granted to You under this License for that Work shall terminate
87
+      as of the date such litigation is filed.
88
+
89
+   4. Redistribution. You may reproduce and distribute copies of the
90
+      Work or Derivative Works thereof in any medium, with or without
91
+      modifications, and in Source or Object form, provided that You
92
+      meet the following conditions:
93
+
94
+      (a) You must give any other recipients of the Work or
95
+          Derivative Works a copy of this License; and
96
+
97
+      (b) You must cause any modified files to carry prominent notices
98
+          stating that You changed the files; and
99
+
100
+      (c) You must retain, in the Source form of any Derivative Works
101
+          that You distribute, all copyright, patent, trademark, and
102
+          attribution notices from the Source form of the Work,
103
+          excluding those notices that do not pertain to any part of
104
+          the Derivative Works; and
105
+
106
+      (d) If the Work includes a "NOTICE" text file as part of its
107
+          distribution, then any Derivative Works that You distribute must
108
+          include a readable copy of the attribution notices contained
109
+          within such NOTICE file, excluding those notices that do not
110
+          pertain to any part of the Derivative Works, in at least one
111
+          of the following places: within a NOTICE text file distributed
112
+          as part of the Derivative Works; within the Source form or
113
+          documentation, if provided along with the Derivative Works; or,
114
+          within a display generated by the Derivative Works, if and
115
+          wherever such third-party notices normally appear. The contents
116
+          of the NOTICE file are for informational purposes only and
117
+          do not modify the License. You may add Your own attribution
118
+          notices within Derivative Works that You distribute, alongside
119
+          or as an addendum to the NOTICE text from the Work, provided
120
+          that such additional attribution notices cannot be construed
121
+          as modifying the License.
122
+
123
+      You may add Your own copyright statement to Your modifications and
124
+      may provide additional or different license terms and conditions
125
+      for use, reproduction, or distribution of Your modifications, or
126
+      for any such Derivative Works as a whole, provided Your use,
127
+      reproduction, and distribution of the Work otherwise complies with
128
+      the conditions stated in this License.
129
+
130
+   5. Submission of Contributions. Unless You explicitly state otherwise,
131
+      any Contribution intentionally submitted for inclusion in the Work
132
+      by You to the Licensor shall be under the terms and conditions of
133
+      this License, without any additional terms or conditions.
134
+      Notwithstanding the above, nothing herein shall supersede or modify
135
+      the terms of any separate license agreement you may have executed
136
+      with Licensor regarding such Contributions.
137
+
138
+   6. Trademarks. This License does not grant permission to use the trade
139
+      names, trademarks, service marks, or product names of the Licensor,
140
+      except as required for reasonable and customary use in describing the
141
+      origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+   7. Disclaimer of Warranty. Unless required by applicable law or
144
+      agreed to in writing, Licensor provides the Work (and each
145
+      Contributor provides its Contributions) on an "AS IS" BASIS,
146
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+      implied, including, without limitation, any warranties or conditions
148
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+      PARTICULAR PURPOSE. You are solely responsible for determining the
150
+      appropriateness of using or redistributing the Work and assume any
151
+      risks associated with Your exercise of permissions under this License.
152
+
153
+   8. Limitation of Liability. In no event and under no legal theory,
154
+      whether in tort (including negligence), contract, or otherwise,
155
+      unless required by applicable law (such as deliberate and grossly
156
+      negligent acts) or agreed to in writing, shall any Contributor be
157
+      liable to You for damages, including any direct, indirect, special,
158
+      incidental, or consequential damages of any character arising as a
159
+      result of this License or out of the use or inability to use the
160
+      Work (including but not limited to damages for loss of goodwill,
161
+      work stoppage, computer failure or malfunction, or any and all
162
+      other commercial damages or losses), even if such Contributor
163
+      has been advised of the possibility of such damages.
164
+
165
+   9. Accepting Warranty or Additional Liability. While redistributing
166
+      the Work or Derivative Works thereof, You may choose to offer,
167
+      and charge a fee for, acceptance of support, warranty, indemnity,
168
+      or other liability obligations and/or rights consistent with this
169
+      License. However, in accepting such obligations, You may act only
170
+      on Your own behalf and on Your sole responsibility, not on behalf
171
+      of any other Contributor, and only if You agree to indemnify,
172
+      defend, and hold each Contributor harmless for any liability
173
+      incurred by, or claims asserted against, such Contributor by reason
174
+      of your accepting any such warranty or additional liability.
175
+
176
+   END OF TERMS AND CONDITIONS
177
+
178
+   APPENDIX: How to apply the Apache License to your work.
179
+
180
+      To apply the Apache License to your work, attach the following
181
+      boilerplate notice, with the fields enclosed by brackets "[]"
182
+      replaced with your own identifying information. (Don't include
183
+      the brackets!)  The text should be enclosed in the appropriate
184
+      comment syntax for the file format. We also recommend that a
185
+      file or class name and description of purpose be included on the
186
+      same "printed page" as the copyright notice for easier
187
+      identification within third-party archives.
188
+
189
+   Copyright [yyyy] [name of copyright owner]
190
+
191
+   Licensed under the Apache License, Version 2.0 (the "License");
192
+   you may not use this file except in compliance with the License.
193
+   You may obtain a copy of the License at
194
+
195
+       http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+   Unless required by applicable law or agreed to in writing, software
198
+   distributed under the License is distributed on an "AS IS" BASIS,
199
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+   See the License for the specific language governing permissions and
201
+   limitations under the License.

+ 20
- 0
vendor/code.cloudfoundry.org/bytefmt/NOTICE View File

@@ -0,0 +1,20 @@
1
+Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved.
2
+
3
+This project contains software that is Copyright (c) 2013-2015 Pivotal Software, Inc.
4
+
5
+Licensed under the Apache License, Version 2.0 (the "License");
6
+you may not use this file except in compliance with the License.
7
+You may obtain a copy of the License at
8
+
9
+   http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+Unless required by applicable law or agreed to in writing, software
12
+distributed under the License is distributed on an "AS IS" BASIS,
13
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+See the License for the specific language governing permissions and
15
+limitations under the License.
16
+
17
+This project may include a number of subcomponents with separate
18
+copyright notices and license terms. Your use of these subcomponents
19
+is subject to the terms and conditions of each subcomponent's license,
20
+as noted in the LICENSE file.

+ 15
- 0
vendor/code.cloudfoundry.org/bytefmt/README.md View File

@@ -0,0 +1,15 @@
1
+bytefmt
2
+=======
3
+
4
+**Note**: This repository should be imported as `code.cloudfoundry.org/bytefmt`.
5
+
6
+Human-readable byte formatter.
7
+
8
+Example:
9
+
10
+```go
11
+bytefmt.ByteSize(100.5*bytefmt.MEGABYTE) // returns "100.5M"
12
+bytefmt.ByteSize(uint64(1024)) // returns "1K"
13
+```
14
+
15
+For documentation, please see http://godoc.org/code.cloudfoundry.org/bytefmt

+ 121
- 0
vendor/code.cloudfoundry.org/bytefmt/bytes.go View File

@@ -0,0 +1,121 @@
1
+// Package bytefmt contains helper methods and constants for converting to and from a human-readable byte format.
2
+//
3
+//	bytefmt.ByteSize(100.5*bytefmt.MEGABYTE) // "100.5M"
4
+//	bytefmt.ByteSize(uint64(1024)) // "1K"
5
+//
6
+package bytefmt
7
+
8
+import (
9
+	"errors"
10
+	"strconv"
11
+	"strings"
12
+	"unicode"
13
+)
14
+
15
+const (
16
+	BYTE = 1 << (10 * iota)
17
+	KILOBYTE
18
+	MEGABYTE
19
+	GIGABYTE
20
+	TERABYTE
21
+	PETABYTE
22
+	EXABYTE
23
+)
24
+
25
+var invalidByteQuantityError = errors.New("byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB")
26
+
27
+// ByteSize returns a human-readable byte string of the form 10M, 12.5K, and so forth.  The following units are available:
28
+//	E: Exabyte
29
+//	P: Petabyte
30
+//	T: Terabyte
31
+//	G: Gigabyte
32
+//	M: Megabyte
33
+//	K: Kilobyte
34
+//	B: Byte
35
+// The unit that results in the smallest number greater than or equal to 1 is always chosen.
36
+func ByteSize(bytes uint64) string {
37
+	unit := ""
38
+	value := float64(bytes)
39
+
40
+	switch {
41
+	case bytes >= EXABYTE:
42
+		unit = "E"
43
+		value = value / EXABYTE
44
+	case bytes >= PETABYTE:
45
+		unit = "P"
46
+		value = value / PETABYTE
47
+	case bytes >= TERABYTE:
48
+		unit = "T"
49
+		value = value / TERABYTE
50
+	case bytes >= GIGABYTE:
51
+		unit = "G"
52
+		value = value / GIGABYTE
53
+	case bytes >= MEGABYTE:
54
+		unit = "M"
55
+		value = value / MEGABYTE
56
+	case bytes >= KILOBYTE:
57
+		unit = "K"
58
+		value = value / KILOBYTE
59
+	case bytes >= BYTE:
60
+		unit = "B"
61
+	case bytes == 0:
62
+		return "0B"
63
+	}
64
+
65
+	result := strconv.FormatFloat(value, 'f', 1, 64)
66
+	result = strings.TrimSuffix(result, ".0")
67
+	return result + unit
68
+}
69
+
70
+// ToMegabytes parses a string formatted by ByteSize as megabytes.
71
+func ToMegabytes(s string) (uint64, error) {
72
+	bytes, err := ToBytes(s)
73
+	if err != nil {
74
+		return 0, err
75
+	}
76
+
77
+	return bytes / MEGABYTE, nil
78
+}
79
+
80
+// ToBytes parses a string formatted by ByteSize as bytes. Note binary-prefixed and SI prefixed units both mean a base-2 units
81
+// KB = K = KiB	= 1024
82
+// MB = M = MiB = 1024 * K
83
+// GB = G = GiB = 1024 * M
84
+// TB = T = TiB = 1024 * G
85
+// PB = P = PiB = 1024 * T
86
+// EB = E = EiB = 1024 * P
87
+func ToBytes(s string) (uint64, error) {
88
+	s = strings.TrimSpace(s)
89
+	s = strings.ToUpper(s)
90
+
91
+	i := strings.IndexFunc(s, unicode.IsLetter)
92
+
93
+	if i == -1 {
94
+		return 0, invalidByteQuantityError
95
+	}
96
+
97
+	bytesString, multiple := s[:i], s[i:]
98
+	bytes, err := strconv.ParseFloat(bytesString, 64)
99
+	if err != nil || bytes < 0 {
100
+		return 0, invalidByteQuantityError
101
+	}
102
+
103
+	switch multiple {
104
+	case "E", "EB", "EIB":
105
+		return uint64(bytes * EXABYTE), nil
106
+	case "P", "PB", "PIB":
107
+		return uint64(bytes * PETABYTE), nil
108
+	case "T", "TB", "TIB":
109
+		return uint64(bytes * TERABYTE), nil
110
+	case "G", "GB", "GIB":
111
+		return uint64(bytes * GIGABYTE), nil
112
+	case "M", "MB", "MIB":
113
+		return uint64(bytes * MEGABYTE), nil
114
+	case "K", "KB", "KIB":
115
+		return uint64(bytes * KILOBYTE), nil
116
+	case "B":
117
+		return uint64(bytes), nil
118
+	default:
119
+		return 0, invalidByteQuantityError
120
+	}
121
+}

+ 1
- 0
vendor/code.cloudfoundry.org/bytefmt/package.go View File

@@ -0,0 +1 @@
1
+package bytefmt // import "code.cloudfoundry.org/bytefmt"

+ 25
- 0
vendor/github.com/docopt/docopt-go/.gitignore View File

@@ -0,0 +1,25 @@
1
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
2
+*.o
3
+*.a
4
+*.so
5
+
6
+# Folders
7
+_obj
8
+_test
9
+
10
+# Architecture specific extensions/prefixes
11
+*.[568vq]
12
+[568vq].out
13
+
14
+*.cgo1.go
15
+*.cgo2.c
16
+_cgo_defun.c
17
+_cgo_gotypes.go
18
+_cgo_export.*
19
+
20
+_testmain.go
21
+
22
+*.exe
23
+
24
+# coverage droppings
25
+profile.cov

+ 32
- 0
vendor/github.com/docopt/docopt-go/.travis.yml View File

@@ -0,0 +1,32 @@
1
+# Travis CI (http://travis-ci.org/) is a continuous integration
2
+# service for open source projects. This file configures it
3
+# to run unit tests for docopt-go.
4
+
5
+language: go
6
+
7
+go:
8
+    - 1.4
9
+    - 1.5
10
+    - 1.6
11
+    - 1.7
12
+    - 1.8
13
+    - 1.9
14
+    - tip
15
+
16
+matrix:
17
+    fast_finish: true
18
+
19
+before_install:
20
+    - go get golang.org/x/tools/cmd/cover
21
+    - go get github.com/mattn/goveralls
22
+
23
+install:
24
+    - go get -d -v ./... && go build -v ./...
25
+
26
+script:
27
+    - go vet -x ./...
28
+    - go test -v ./...
29
+    - go test -covermode=count -coverprofile=profile.cov .
30
+
31
+after_script:
32
+    - $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci

+ 21
- 0
vendor/github.com/docopt/docopt-go/LICENSE View File

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

+ 116
- 0
vendor/github.com/docopt/docopt-go/README.md View File

@@ -0,0 +1,116 @@
1
+docopt-go
2
+=========
3
+
4
+[![Build Status](https://travis-ci.org/docopt/docopt.go.svg?branch=master)](https://travis-ci.org/docopt/docopt.go)
5
+[![Coverage Status](https://coveralls.io/repos/github/docopt/docopt.go/badge.svg)](https://coveralls.io/github/docopt/docopt.go)
6
+[![GoDoc](https://godoc.org/github.com/docopt/docopt.go?status.svg)](https://godoc.org/github.com/docopt/docopt.go)
7
+
8
+An implementation of [docopt](http://docopt.org/) in the [Go](http://golang.org/) programming language.
9
+
10
+**docopt** helps you create *beautiful* command-line interfaces easily:
11
+
12
+```go
13
+package main
14
+
15
+import (
16
+	"fmt"
17
+	"github.com/docopt/docopt-go"
18
+)
19
+
20
+func main() {
21
+	  usage := `Naval Fate.
22
+
23
+Usage:
24
+  naval_fate ship new <name>...
25
+  naval_fate ship <name> move <x> <y> [--speed=<kn>]
26
+  naval_fate ship shoot <x> <y>
27
+  naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
28
+  naval_fate -h | --help
29
+  naval_fate --version
30
+
31
+Options:
32
+  -h --help     Show this screen.
33
+  --version     Show version.
34
+  --speed=<kn>  Speed in knots [default: 10].
35
+  --moored      Moored (anchored) mine.
36
+  --drifting    Drifting mine.`
37
+
38
+	  arguments, _ := docopt.ParseDoc(usage)
39
+	  fmt.Println(arguments)
40
+}
41
+```
42
+
43
+**docopt** parses command-line arguments based on a help message. Don't write parser code: a good help message already has all the necessary information in it.
44
+
45
+## Installation
46
+
47
+⚠ Use the alias "docopt-go". To use docopt in your Go code:
48
+
49
+```go
50
+import "github.com/docopt/docopt-go"
51
+```
52
+
53
+To install docopt in your `$GOPATH`:
54
+
55
+```console
56
+$ go get github.com/docopt/docopt-go
57
+```
58
+
59
+## API
60
+
61
+Given a conventional command-line help message, docopt processes the arguments. See https://github.com/docopt/docopt#help-message-format for a description of the help message format.
62
+
63
+This package exposes three different APIs, depending on the level of control required. The first, simplest way to parse your docopt usage is to just call:
64
+
65
+```go
66
+docopt.ParseDoc(usage)
67
+```
68
+
69
+This will use `os.Args[1:]` as the argv slice, and use the default parser options. If you want to provide your own version string and args, then use:
70
+
71
+```go
72
+docopt.ParseArgs(usage, argv, "1.2.3")
73
+```
74
+
75
+If the last parameter (version) is a non-empty string, it will be printed when `--version` is given in the argv slice. Finally, we can instantiate our own `docopt.Parser` which gives us control over how things like help messages are printed and whether to exit after displaying usage messages, etc.
76
+
77
+```go
78
+parser := &docopt.Parser{
79
+  HelpHandler: docopt.PrintHelpOnly,
80
+  OptionsFirst: true,
81
+}
82
+opts, err := parser.ParseArgs(usage, argv, "")
83
+```
84
+
85
+In particular, setting your own custom `HelpHandler` function makes unit testing your own docs with example command line invocations much more enjoyable.
86
+
87
+All three of these return a map of option names to the values parsed from argv, and an error or nil. You can get the values using the helpers, or just treat it as a regular map:
88
+
89
+```go
90
+flag, _ := opts.Bool("--flag")
91
+secs, _ := opts.Int("<seconds>")
92
+```
93
+
94
+Additionally, you can `Bind` these to a struct, assigning option values to the
95
+exported fields of that struct, all at once.
96
+
97
+```go
98
+var config struct {
99
+  Command string `docopt:"<cmd>"`
100
+  Tries   int    `docopt:"-n"`
101
+  Force   bool   // Gets the value of --force
102
+}
103
+opts.Bind(&config)
104
+```
105
+
106
+More documentation is available at [godoc.org](https://godoc.org/github.com/docopt/docopt-go).
107
+
108
+## Unit Testing
109
+
110
+Unit testing your own usage docs is recommended, so you can be sure that for a given command line invocation, the expected options are set. An example of how to do this is [in the examples folder](examples/unit_test/unit_test.go).
111
+
112
+## Tests
113
+
114
+All tests from the Python version are implemented and passing at [Travis CI](https://travis-ci.org/docopt/docopt-go). New language-agnostic tests have been added to [test_golang.docopt](test_golang.docopt).
115
+
116
+To run tests for docopt-go, use `go test`.

+ 49
- 0
vendor/github.com/docopt/docopt-go/doc.go View File

@@ -0,0 +1,49 @@
1
+/*
2
+Package docopt parses command-line arguments based on a help message.
3
+
4
+Given a conventional command-line help message, docopt processes the arguments.
5
+See https://github.com/docopt/docopt#help-message-format for a description of
6
+the help message format.
7
+
8
+This package exposes three different APIs, depending on the level of control
9
+required. The first, simplest way to parse your docopt usage is to just call:
10
+
11
+	docopt.ParseDoc(usage)
12
+
13
+This will use os.Args[1:] as the argv slice, and use the default parser
14
+options. If you want to provide your own version string and args, then use:
15
+
16
+	docopt.ParseArgs(usage, argv, "1.2.3")
17
+
18
+If the last parameter (version) is a non-empty string, it will be printed when
19
+--version is given in the argv slice. Finally, we can instantiate our own
20
+docopt.Parser which gives us control over how things like help messages are
21
+printed and whether to exit after displaying usage messages, etc.
22
+
23
+	parser := &docopt.Parser{
24
+		HelpHandler: docopt.PrintHelpOnly,
25
+		OptionsFirst: true,
26
+	}
27
+	opts, err := parser.ParseArgs(usage, argv, "")
28
+
29
+In particular, setting your own custom HelpHandler function makes unit testing
30
+your own docs with example command line invocations much more enjoyable.
31
+
32
+All three of these return a map of option names to the values parsed from argv,
33
+and an error or nil. You can get the values using the helpers, or just treat it
34
+as a regular map:
35
+
36
+	flag, _ := opts.Bool("--flag")
37
+	secs, _ := opts.Int("<seconds>")
38
+
39
+Additionally, you can `Bind` these to a struct, assigning option values to the
40
+exported fields of that struct, all at once.
41
+
42
+	var config struct {
43
+		Command string `docopt:"<cmd>"`
44
+		Tries   int    `docopt:"-n"`
45
+		Force   bool   // Gets the value of --force
46
+	}
47
+	opts.Bind(&config)
48
+*/
49
+package docopt

+ 575
- 0
vendor/github.com/docopt/docopt-go/docopt.go View File

@@ -0,0 +1,575 @@
1
+// Licensed under terms of MIT license (see LICENSE-MIT)
2
+// Copyright (c) 2013 Keith Batten, kbatten@gmail.com
3
+// Copyright (c) 2016 David Irvine
4
+
5
+package docopt
6
+
7
+import (
8
+	"fmt"
9
+	"os"
10
+	"regexp"
11
+	"strings"
12
+)
13
+
14
+type Parser struct {
15
+	// HelpHandler is called when we encounter bad user input, or when the user
16
+	// asks for help.
17
+	// By default, this calls os.Exit(0) if it handled a built-in option such
18
+	// as -h, --help or --version. If the user errored with a wrong command or
19
+	// options, we exit with a return code of 1.
20
+	HelpHandler func(err error, usage string)
21
+	// OptionsFirst requires that option flags always come before positional
22
+	// arguments; otherwise they can overlap.
23
+	OptionsFirst bool
24
+	// SkipHelpFlags tells the parser not to look for -h and --help flags and
25
+	// call the HelpHandler.
26
+	SkipHelpFlags bool
27
+}
28
+
29
+var PrintHelpAndExit = func(err error, usage string) {
30
+	if err != nil {
31
+		fmt.Fprintln(os.Stderr, usage)
32
+		os.Exit(1)
33
+	} else {
34
+		fmt.Println(usage)
35
+		os.Exit(0)
36
+	}
37
+}
38
+
39
+var PrintHelpOnly = func(err error, usage string) {
40
+	if err != nil {
41
+		fmt.Fprintln(os.Stderr, usage)
42
+	} else {
43
+		fmt.Println(usage)
44
+	}
45
+}
46
+
47
+var NoHelpHandler = func(err error, usage string) {}
48
+
49
+var DefaultParser = &Parser{
50
+	HelpHandler:   PrintHelpAndExit,
51
+	OptionsFirst:  false,
52
+	SkipHelpFlags: false,
53
+}
54
+
55
+// ParseDoc parses os.Args[1:] based on the interface described in doc, using the default parser options.
56
+func ParseDoc(doc string) (Opts, error) {
57
+	return ParseArgs(doc, nil, "")
58
+}
59
+
60
+// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
61
+// string, then this will be displayed when the --version flag is found. This method uses the default parser options.
62
+func ParseArgs(doc string, argv []string, version string) (Opts, error) {
63
+	return DefaultParser.ParseArgs(doc, argv, version)
64
+}
65
+
66
+// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
67
+// string, then this will be displayed when the --version flag is found.
68
+func (p *Parser) ParseArgs(doc string, argv []string, version string) (Opts, error) {
69
+	return p.parse(doc, argv, version)
70
+}
71
+
72
+// Deprecated: Parse is provided for backward compatibility with the original docopt.go package.
73
+// Please rather make use of ParseDoc, ParseArgs, or use your own custom Parser.
74
+func Parse(doc string, argv []string, help bool, version string, optionsFirst bool, exit ...bool) (map[string]interface{}, error) {
75
+	exitOk := true
76
+	if len(exit) > 0 {
77
+		exitOk = exit[0]
78
+	}
79
+	p := &Parser{
80
+		OptionsFirst:  optionsFirst,
81
+		SkipHelpFlags: !help,
82
+	}
83
+	if exitOk {
84
+		p.HelpHandler = PrintHelpAndExit
85
+	} else {
86
+		p.HelpHandler = PrintHelpOnly
87
+	}
88
+	return p.parse(doc, argv, version)
89
+}
90
+
91
+func (p *Parser) parse(doc string, argv []string, version string) (map[string]interface{}, error) {
92
+	if argv == nil {
93
+		argv = os.Args[1:]
94
+	}
95
+	if p.HelpHandler == nil {
96
+		p.HelpHandler = DefaultParser.HelpHandler
97
+	}
98
+	args, output, err := parse(doc, argv, !p.SkipHelpFlags, version, p.OptionsFirst)
99
+	if _, ok := err.(*UserError); ok {
100
+		// the user gave us bad input
101
+		p.HelpHandler(err, output)
102
+	} else if len(output) > 0 && err == nil {
103
+		// the user asked for help or --version
104
+		p.HelpHandler(err, output)
105
+	}
106
+	return args, err
107
+}
108
+
109
+// -----------------------------------------------------------------------------
110
+
111
+// parse and return a map of args, output and all errors
112
+func parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) {
113
+	if argv == nil && len(os.Args) > 1 {
114
+		argv = os.Args[1:]
115
+	}
116
+
117
+	usageSections := parseSection("usage:", doc)
118
+
119
+	if len(usageSections) == 0 {
120
+		err = newLanguageError("\"usage:\" (case-insensitive) not found.")
121
+		return
122
+	}
123
+	if len(usageSections) > 1 {
124
+		err = newLanguageError("More than one \"usage:\" (case-insensitive).")
125
+		return
126
+	}
127
+	usage := usageSections[0]
128
+
129
+	options := parseDefaults(doc)
130
+	formal, err := formalUsage(usage)
131
+	if err != nil {
132
+		output = handleError(err, usage)
133
+		return
134
+	}
135
+
136
+	pat, err := parsePattern(formal, &options)
137
+	if err != nil {
138
+		output = handleError(err, usage)
139
+		return
140
+	}
141
+
142
+	patternArgv, err := parseArgv(newTokenList(argv, errorUser), &options, optionsFirst)
143
+	if err != nil {
144
+		output = handleError(err, usage)
145
+		return
146
+	}
147
+	patFlat, err := pat.flat(patternOption)
148
+	if err != nil {
149
+		output = handleError(err, usage)
150
+		return
151
+	}
152
+	patternOptions := patFlat.unique()
153
+
154
+	patFlat, err = pat.flat(patternOptionSSHORTCUT)
155
+	if err != nil {
156
+		output = handleError(err, usage)
157
+		return
158
+	}
159
+	for _, optionsShortcut := range patFlat {
160
+		docOptions := parseDefaults(doc)
161
+		optionsShortcut.children = docOptions.unique().diff(patternOptions)
162
+	}
163
+
164
+	if output = extras(help, version, patternArgv, doc); len(output) > 0 {
165
+		return
166
+	}
167
+
168
+	err = pat.fix()
169
+	if err != nil {
170
+		output = handleError(err, usage)
171
+		return
172
+	}
173
+	matched, left, collected := pat.match(&patternArgv, nil)
174
+	if matched && len(*left) == 0 {
175
+		patFlat, err = pat.flat(patternDefault)
176
+		if err != nil {
177
+			output = handleError(err, usage)
178
+			return
179
+		}
180
+		args = append(patFlat, *collected...).dictionary()
181
+		return
182
+	}
183
+
184
+	err = newUserError("")
185
+	output = handleError(err, usage)
186
+	return
187
+}
188
+
189
+func handleError(err error, usage string) string {
190
+	if _, ok := err.(*UserError); ok {
191
+		return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage))
192
+	}
193
+	return ""
194
+}
195
+
196
+func parseSection(name, source string) []string {
197
+	p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`)
198
+	s := p.FindAllString(source, -1)
199
+	if s == nil {
200
+		s = []string{}
201
+	}
202
+	for i, v := range s {
203
+		s[i] = strings.TrimSpace(v)
204
+	}
205
+	return s
206
+}
207
+
208
+func parseDefaults(doc string) patternList {
209
+	defaults := patternList{}
210
+	p := regexp.MustCompile(`\n[ \t]*(-\S+?)`)
211
+	for _, s := range parseSection("options:", doc) {
212
+		// FIXME corner case "bla: options: --foo"
213
+		_, _, s = stringPartition(s, ":") // get rid of "options:"
214
+		split := p.Split("\n"+s, -1)[1:]
215
+		match := p.FindAllStringSubmatch("\n"+s, -1)
216
+		for i := range split {
217
+			optionDescription := match[i][1] + split[i]
218
+			if strings.HasPrefix(optionDescription, "-") {
219
+				defaults = append(defaults, parseOption(optionDescription))
220
+			}
221
+		}
222
+	}
223
+	return defaults
224
+}
225
+
226
+func parsePattern(source string, options *patternList) (*pattern, error) {
227
+	tokens := tokenListFromPattern(source)
228
+	result, err := parseExpr(tokens, options)
229
+	if err != nil {
230
+		return nil, err
231
+	}
232
+	if tokens.current() != nil {
233
+		return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " "))
234
+	}
235
+	return newRequired(result...), nil
236
+}
237
+
238
+func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) {
239
+	/*
240
+		Parse command-line argument vector.
241
+
242
+		If options_first:
243
+			argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
244
+		else:
245
+			argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
246
+	*/
247
+	parsed := patternList{}
248
+	for tokens.current() != nil {
249
+		if tokens.current().eq("--") {
250
+			for _, v := range tokens.tokens {
251
+				parsed = append(parsed, newArgument("", v))
252
+			}
253
+			return parsed, nil
254
+		} else if tokens.current().hasPrefix("--") {
255
+			pl, err := parseLong(tokens, options)
256
+			if err != nil {
257
+				return nil, err
258
+			}
259
+			parsed = append(parsed, pl...)
260
+		} else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") {
261
+			ps, err := parseShorts(tokens, options)
262
+			if err != nil {
263
+				return nil, err
264
+			}
265
+			parsed = append(parsed, ps...)
266
+		} else if optionsFirst {
267
+			for _, v := range tokens.tokens {
268
+				parsed = append(parsed, newArgument("", v))
269
+			}
270
+			return parsed, nil
271
+		} else {
272
+			parsed = append(parsed, newArgument("", tokens.move().String()))
273
+		}
274
+	}
275
+	return parsed, nil
276
+}
277
+
278
+func parseOption(optionDescription string) *pattern {
279
+	optionDescription = strings.TrimSpace(optionDescription)
280
+	options, _, description := stringPartition(optionDescription, "  ")
281
+	options = strings.Replace(options, ",", " ", -1)
282
+	options = strings.Replace(options, "=", " ", -1)
283
+
284
+	short := ""
285
+	long := ""
286
+	argcount := 0
287
+	var value interface{}
288
+	value = false
289
+
290
+	reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`)
291
+	for _, s := range strings.Fields(options) {
292
+		if strings.HasPrefix(s, "--") {
293
+			long = s
294
+		} else if strings.HasPrefix(s, "-") {
295
+			short = s
296
+		} else {
297
+			argcount = 1
298
+		}
299
+		if argcount > 0 {
300
+			matched := reDefault.FindAllStringSubmatch(description, -1)
301
+			if len(matched) > 0 {
302
+				value = matched[0][1]
303
+			} else {
304
+				value = nil
305
+			}
306
+		}
307
+	}
308
+	return newOption(short, long, argcount, value)
309
+}
310
+
311
+func parseExpr(tokens *tokenList, options *patternList) (patternList, error) {
312
+	// expr ::= seq ( '|' seq )* ;
313
+	seq, err := parseSeq(tokens, options)
314
+	if err != nil {
315
+		return nil, err
316
+	}
317
+	if !tokens.current().eq("|") {
318
+		return seq, nil
319
+	}
320
+	var result patternList
321
+	if len(seq) > 1 {
322
+		result = patternList{newRequired(seq...)}
323
+	} else {
324
+		result = seq
325
+	}
326
+	for tokens.current().eq("|") {
327
+		tokens.move()
328
+		seq, err = parseSeq(tokens, options)
329
+		if err != nil {
330
+			return nil, err
331
+		}
332
+		if len(seq) > 1 {
333
+			result = append(result, newRequired(seq...))
334
+		} else {
335
+			result = append(result, seq...)
336
+		}
337
+	}
338
+	if len(result) > 1 {
339
+		return patternList{newEither(result...)}, nil
340
+	}
341
+	return result, nil
342
+}
343
+
344
+func parseSeq(tokens *tokenList, options *patternList) (patternList, error) {
345
+	// seq ::= ( atom [ '...' ] )* ;
346
+	result := patternList{}
347
+	for !tokens.current().match(true, "]", ")", "|") {
348
+		atom, err := parseAtom(tokens, options)
349
+		if err != nil {
350
+			return nil, err
351
+		}
352
+		if tokens.current().eq("...") {
353
+			atom = patternList{newOneOrMore(atom...)}
354
+			tokens.move()
355
+		}
356
+		result = append(result, atom...)
357
+	}
358
+	return result, nil
359
+}
360
+
361
+func parseAtom(tokens *tokenList, options *patternList) (patternList, error) {
362
+	// atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ;
363
+	tok := tokens.current()
364
+	result := patternList{}
365
+	if tokens.current().match(false, "(", "[") {
366
+		tokens.move()
367
+		var matching string
368
+		pl, err := parseExpr(tokens, options)
369
+		if err != nil {
370
+			return nil, err
371
+		}
372
+		if tok.eq("(") {
373
+			matching = ")"
374
+			result = patternList{newRequired(pl...)}
375
+		} else if tok.eq("[") {
376
+			matching = "]"
377
+			result = patternList{newOptional(pl...)}
378
+		}
379
+		moved := tokens.move()
380
+		if !moved.eq(matching) {
381
+			return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved)
382
+		}
383
+		return result, nil
384
+	} else if tok.eq("options") {
385
+		tokens.move()
386
+		return patternList{newOptionsShortcut()}, nil
387
+	} else if tok.hasPrefix("--") && !tok.eq("--") {
388
+		return parseLong(tokens, options)
389
+	} else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") {
390
+		return parseShorts(tokens, options)
391
+	} else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() {
392
+		return patternList{newArgument(tokens.move().String(), nil)}, nil
393
+	}
394
+	return patternList{newCommand(tokens.move().String(), false)}, nil
395
+}
396
+
397
+func parseLong(tokens *tokenList, options *patternList) (patternList, error) {
398
+	// long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
399
+	long, eq, v := stringPartition(tokens.move().String(), "=")
400
+	var value interface{}
401
+	var opt *pattern
402
+	if eq == "" && v == "" {
403
+		value = nil
404
+	} else {
405
+		value = v
406
+	}
407
+
408
+	if !strings.HasPrefix(long, "--") {
409
+		return nil, newError("long option '%s' doesn't start with --", long)
410
+	}
411
+	similar := patternList{}
412
+	for _, o := range *options {
413
+		if o.long == long {
414
+			similar = append(similar, o)
415
+		}
416
+	}
417
+	if tokens.err == errorUser && len(similar) == 0 { // if no exact match
418
+		similar = patternList{}
419
+		for _, o := range *options {
420
+			if strings.HasPrefix(o.long, long) {
421
+				similar = append(similar, o)
422
+			}
423
+		}
424
+	}
425
+	if len(similar) > 1 { // might be simply specified ambiguously 2+ times?
426
+		similarLong := make([]string, len(similar))
427
+		for i, s := range similar {
428
+			similarLong[i] = s.long
429
+		}
430
+		return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", "))
431
+	} else if len(similar) < 1 {
432
+		argcount := 0
433
+		if eq == "=" {
434
+			argcount = 1
435
+		}
436
+		opt = newOption("", long, argcount, false)
437
+		*options = append(*options, opt)
438
+		if tokens.err == errorUser {
439
+			var val interface{}
440
+			if argcount > 0 {
441
+				val = value
442
+			} else {
443
+				val = true
444
+			}
445
+			opt = newOption("", long, argcount, val)
446
+		}
447
+	} else {
448
+		opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value)
449
+		if opt.argcount == 0 {
450
+			if value != nil {
451
+				return nil, tokens.errorFunc("%s must not have an argument", opt.long)
452
+			}
453
+		} else {
454
+			if value == nil {
455
+				if tokens.current().match(true, "--") {
456
+					return nil, tokens.errorFunc("%s requires argument", opt.long)
457
+				}
458
+				moved := tokens.move()
459
+				if moved != nil {
460
+					value = moved.String() // only set as string if not nil
461
+				}
462
+			}
463
+		}
464
+		if tokens.err == errorUser {
465
+			if value != nil {
466
+				opt.value = value
467
+			} else {
468
+				opt.value = true
469
+			}
470
+		}
471
+	}
472
+
473
+	return patternList{opt}, nil
474
+}
475
+
476
+func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
477
+	// shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
478
+	tok := tokens.move()
479
+	if !tok.hasPrefix("-") || tok.hasPrefix("--") {
480
+		return nil, newError("short option '%s' doesn't start with -", tok)
481
+	}
482
+	left := strings.TrimLeft(tok.String(), "-")
483
+	parsed := patternList{}
484
+	for left != "" {
485
+		var opt *pattern
486
+		short := "-" + left[0:1]
487
+		left = left[1:]
488
+		similar := patternList{}
489
+		for _, o := range *options {
490
+			if o.short == short {
491
+				similar = append(similar, o)
492
+			}
493
+		}
494
+		if len(similar) > 1 {
495
+			return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar))
496
+		} else if len(similar) < 1 {
497
+			opt = newOption(short, "", 0, false)
498
+			*options = append(*options, opt)
499
+			if tokens.err == errorUser {
500
+				opt = newOption(short, "", 0, true)
501
+			}
502
+		} else { // why copying is necessary here?
503
+			opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value)
504
+			var value interface{}
505
+			if opt.argcount > 0 {
506
+				if left == "" {
507
+					if tokens.current().match(true, "--") {
508
+						return nil, tokens.errorFunc("%s requires argument", short)
509
+					}
510
+					value = tokens.move().String()
511
+				} else {
512
+					value = left
513
+					left = ""
514
+				}
515
+			}
516
+			if tokens.err == errorUser {
517
+				if value != nil {
518
+					opt.value = value
519
+				} else {
520
+					opt.value = true
521
+				}
522
+			}
523
+		}
524
+		parsed = append(parsed, opt)
525
+	}
526
+	return parsed, nil
527
+}
528
+
529
+func formalUsage(section string) (string, error) {
530
+	_, _, section = stringPartition(section, ":") // drop "usage:"
531
+	pu := strings.Fields(section)
532
+
533
+	if len(pu) == 0 {
534
+		return "", newLanguageError("no fields found in usage (perhaps a spacing error).")
535
+	}
536
+
537
+	result := "( "
538
+	for _, s := range pu[1:] {
539
+		if s == pu[0] {
540
+			result += ") | ( "
541
+		} else {
542
+			result += s + " "
543
+		}
544
+	}
545
+	result += ")"
546
+
547
+	return result, nil
548
+}
549
+
550
+func extras(help bool, version string, options patternList, doc string) string {
551
+	if help {
552
+		for _, o := range options {
553
+			if (o.name == "-h" || o.name == "--help") && o.value == true {
554
+				return strings.Trim(doc, "\n")
555
+			}
556
+		}
557
+	}
558
+	if version != "" {
559
+		for _, o := range options {
560
+			if (o.name == "--version") && o.value == true {
561
+				return version
562
+			}
563
+		}
564
+	}
565
+	return ""
566
+}
567
+
568
+func stringPartition(s, sep string) (string, string, string) {
569
+	sepPos := strings.Index(s, sep)
570
+	if sepPos == -1 { // no seperator found
571
+		return s, "", ""
572
+	}
573
+	split := strings.SplitN(s, sep, 2)
574
+	return split[0], sep, split[1]
575
+}

+ 49
- 0
vendor/github.com/docopt/docopt-go/error.go View File

@@ -0,0 +1,49 @@
1
+package docopt
2
+
3
+import (
4
+	"fmt"
5
+)
6
+
7
+type errorType int
8
+
9
+const (
10
+	errorUser errorType = iota
11
+	errorLanguage
12
+)
13
+
14
+func (e errorType) String() string {
15
+	switch e {
16
+	case errorUser:
17
+		return "errorUser"
18
+	case errorLanguage:
19
+		return "errorLanguage"
20
+	}
21
+	return ""
22
+}
23
+
24
+// UserError records an error with program arguments.
25
+type UserError struct {
26
+	msg   string
27
+	Usage string
28
+}
29
+
30
+func (e UserError) Error() string {
31
+	return e.msg
32
+}
33
+func newUserError(msg string, f ...interface{}) error {
34
+	return &UserError{fmt.Sprintf(msg, f...), ""}
35
+}
36
+
37
+// LanguageError records an error with the doc string.
38
+type LanguageError struct {
39
+	msg string
40
+}
41
+
42
+func (e LanguageError) Error() string {
43
+	return e.msg
44
+}
45
+func newLanguageError(msg string, f ...interface{}) error {
46
+	return &LanguageError{fmt.Sprintf(msg, f...)}
47
+}
48
+
49
+var newError = fmt.Errorf

+ 264
- 0
vendor/github.com/docopt/docopt-go/opts.go View File

@@ -0,0 +1,264 @@
1
+package docopt
2
+
3
+import (
4
+	"fmt"
5
+	"reflect"
6
+	"strconv"
7
+	"strings"
8
+	"unicode"
9
+)
10
+
11
+func errKey(key string) error {
12
+	return fmt.Errorf("no such key: %q", key)
13
+}
14
+func errType(key string) error {
15
+	return fmt.Errorf("key: %q failed type conversion", key)
16
+}
17
+func errStrconv(key string, convErr error) error {
18
+	return fmt.Errorf("key: %q failed type conversion: %s", key, convErr)
19
+}
20
+
21
+// Opts is a map of command line options to their values, with some convenience
22
+// methods for value type conversion (bool, float64, int, string). For example,
23
+// to get an option value as an int:
24
+//
25
+//   opts, _ := docopt.ParseDoc("Usage: sleep <seconds>")
26
+//   secs, _ := opts.Int("<seconds>")
27
+//
28
+// Additionally, Opts.Bind allows you easily populate a struct's fields with the
29
+// values of each option value. See below for examples.
30
+//
31
+// Lastly, you can still treat Opts as a regular map, and do any type checking
32
+// and conversion that you want to yourself. For example:
33
+//
34
+//   if s, ok := opts["<binary>"].(string); ok {
35
+//     if val, err := strconv.ParseUint(s, 2, 64); err != nil { ... }
36
+//   }
37
+//
38
+// Note that any non-boolean option / flag will have a string value in the
39
+// underlying map.
40
+type Opts map[string]interface{}
41
+
42
+func (o Opts) String(key string) (s string, err error) {
43
+	v, ok := o[key]
44
+	if !ok {
45
+		err = errKey(key)
46
+		return
47
+	}
48
+	s, ok = v.(string)
49
+	if !ok {
50
+		err = errType(key)
51
+	}
52
+	return
53
+}
54
+
55
+func (o Opts) Bool(key string) (b bool, err error) {
56
+	v, ok := o[key]
57
+	if !ok {
58
+		err = errKey(key)
59
+		return
60
+	}
61
+	b, ok = v.(bool)
62
+	if !ok {
63
+		err = errType(key)
64
+	}
65
+	return
66
+}
67
+
68
+func (o Opts) Int(key string) (i int, err error) {
69
+	s, err := o.String(key)
70
+	if err != nil {
71
+		return
72
+	}
73
+	i, err = strconv.Atoi(s)
74
+	if err != nil {
75
+		err = errStrconv(key, err)
76
+	}
77
+	return
78
+}
79
+
80
+func (o Opts) Float64(key string) (f float64, err error) {
81
+	s, err := o.String(key)
82
+	if err != nil {
83
+		return
84
+	}
85
+	f, err = strconv.ParseFloat(s, 64)
86
+	if err != nil {
87
+		err = errStrconv(key, err)
88
+	}
89
+	return
90
+}
91
+
92
+// Bind populates the fields of a given struct with matching option values.
93
+// Each key in Opts will be mapped to an exported field of the struct pointed
94
+// to by `v`, as follows:
95
+//
96
+//   abc int                        // Unexported field, ignored
97
+//   Abc string                     // Mapped from `--abc`, `<abc>`, or `abc`
98
+//                                  // (case insensitive)
99
+//   A string                       // Mapped from `-a`, `<a>` or `a`
100
+//                                  // (case insensitive)
101
+//   Abc int  `docopt:"XYZ"`        // Mapped from `XYZ`
102
+//   Abc bool `docopt:"-"`          // Mapped from `-`
103
+//   Abc bool `docopt:"-x,--xyz"`   // Mapped from `-x` or `--xyz`
104
+//                                  // (first non-zero value found)
105
+//
106
+// Tagged (annotated) fields will always be mapped first. If no field is tagged
107
+// with an option's key, Bind will try to map the option to an appropriately
108
+// named field (as above).
109
+//
110
+// Bind also handles conversion to bool, float, int or string types.
111
+func (o Opts) Bind(v interface{}) error {
112
+	structVal := reflect.ValueOf(v)
113
+	if structVal.Kind() != reflect.Ptr {
114
+		return newError("'v' argument is not pointer to struct type")
115
+	}
116
+	for structVal.Kind() == reflect.Ptr {
117
+		structVal = structVal.Elem()
118
+	}
119
+	if structVal.Kind() != reflect.Struct {
120
+		return newError("'v' argument is not pointer to struct type")
121
+	}
122
+	structType := structVal.Type()
123
+
124
+	tagged := make(map[string]int)   // Tagged field tags
125
+	untagged := make(map[string]int) // Untagged field names
126
+
127
+	for i := 0; i < structType.NumField(); i++ {
128
+		field := structType.Field(i)
129
+		if isUnexportedField(field) || field.Anonymous {
130
+			continue
131
+		}
132
+		tag := field.Tag.Get("docopt")
133
+		if tag == "" {
134
+			untagged[field.Name] = i
135
+			continue
136
+		}
137
+		for _, t := range strings.Split(tag, ",") {
138
+			tagged[t] = i
139
+		}
140
+	}
141
+
142
+	// Get the index of the struct field to use, based on the option key.
143
+	// Second argument is true/false on whether something was matched.
144
+	getFieldIndex := func(key string) (int, bool) {
145
+		if i, ok := tagged[key]; ok {
146
+			return i, true
147
+		}
148
+		if i, ok := untagged[guessUntaggedField(key)]; ok {
149
+			return i, true
150
+		}
151
+		return -1, false
152
+	}
153
+
154
+	indexMap := make(map[string]int) // Option keys to field index
155
+
156
+	// Pre-check that option keys are mapped to fields and fields are zero valued, before populating them.
157
+	for k := range o {
158
+		i, ok := getFieldIndex(k)
159
+		if !ok {
160
+			if k == "--help" || k == "--version" { // Don't require these to be mapped.
161
+				continue
162
+			}
163
+			return newError("mapping of %q is not found in given struct, or is an unexported field", k)
164
+		}
165
+		fieldVal := structVal.Field(i)
166
+		zeroVal := reflect.Zero(fieldVal.Type())
167
+		if !reflect.DeepEqual(fieldVal.Interface(), zeroVal.Interface()) {
168
+			return newError("%q field is non-zero, will be overwritten by value of %q", structType.Field(i).Name, k)
169
+		}
170
+		indexMap[k] = i
171
+	}
172
+
173
+	// Populate fields with option values.
174
+	for k, v := range o {
175
+		i, ok := indexMap[k]
176
+		if !ok {
177
+			continue // Not mapped.
178
+		}
179
+		field := structVal.Field(i)
180
+		if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
181
+			// The struct's field is already non-zero (by our doing), so don't change it.
182
+			// This happens with comma separated tags, e.g. `docopt:"-h,--help"` which is a
183
+			// convenient way of checking if one of multiple boolean flags are set.
184
+			continue
185
+		}
186
+		optVal := reflect.ValueOf(v)
187
+		// Option value is the zero Value, so we can't get its .Type(). No need to assign anyway, so move along.
188
+		if !optVal.IsValid() {
189
+			continue
190
+		}
191
+		if !field.CanSet() {
192
+			return newError("%q field cannot be set", structType.Field(i).Name)
193
+		}
194
+		// Try to assign now if able. bool and string values should be assignable already.
195
+		if optVal.Type().AssignableTo(field.Type()) {
196
+			field.Set(optVal)
197
+			continue
198
+		}
199
+		// Try to convert the value and assign if able.
200
+		switch field.Kind() {
201
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
202
+			if x, err := o.Int(k); err == nil {
203
+				field.SetInt(int64(x))
204
+				continue
205
+			}
206
+		case reflect.Float32, reflect.Float64:
207
+			if x, err := o.Float64(k); err == nil {
208
+				field.SetFloat(x)
209
+				continue
210
+			}
211
+		}
212
+		// TODO: Something clever (recursive?) with non-string slices.
213
+		// case reflect.Slice:
214
+		// 	if optVal.Kind() == reflect.Slice {
215
+		// 		for i := 0; i < optVal.Len(); i++ {
216
+		// 			sliceVal := optVal.Index(i)
217
+		// 			fmt.Printf("%v", sliceVal)
218
+		// 		}
219
+		// 		fmt.Printf("\n")
220
+		// 	}
221
+		return newError("value of %q is not assignable to %q field", k, structType.Field(i).Name)
222
+	}
223
+
224
+	return nil
225
+}
226
+
227
+// isUnexportedField returns whether the field is unexported.
228
+// isUnexportedField is to avoid the bug in versions older than Go1.3.
229
+// See following links:
230
+//   https://code.google.com/p/go/issues/detail?id=7247
231
+//   http://golang.org/ref/spec#Exported_identifiers
232
+func isUnexportedField(field reflect.StructField) bool {
233
+	return !(field.PkgPath == "" && unicode.IsUpper(rune(field.Name[0])))
234
+}
235
+
236
+// Convert a string like "--my-special-flag" to "MySpecialFlag".
237
+func titleCaseDashes(key string) string {
238
+	nextToUpper := true
239
+	mapFn := func(r rune) rune {
240
+		if r == '-' {
241
+			nextToUpper = true
242
+			return -1
243
+		}
244
+		if nextToUpper {
245
+			nextToUpper = false
246
+			return unicode.ToUpper(r)
247
+		}
248
+		return r
249
+	}
250
+	return strings.Map(mapFn, key)
251
+}
252
+
253
+// Best guess which field.Name in a struct to assign for an option key.
254
+func guessUntaggedField(key string) string {
255
+	switch {
256
+	case strings.HasPrefix(key, "--") && len(key[2:]) > 1:
257
+		return titleCaseDashes(key[2:])
258
+	case strings.HasPrefix(key, "-") && len(key[1:]) == 1:
259
+		return titleCaseDashes(key[1:])
260
+	case strings.HasPrefix(key, "<") && strings.HasSuffix(key, ">"):
261
+		key = key[1 : len(key)-1]
262
+	}
263
+	return strings.Title(strings.ToLower(key))
264
+}

+ 550
- 0
vendor/github.com/docopt/docopt-go/pattern.go View File

@@ -0,0 +1,550 @@
1
+package docopt
2
+
3
+import (
4
+	"fmt"
5
+	"reflect"
6
+	"strings"
7
+)
8
+
9
+type patternType uint
10
+
11
+const (
12
+	// leaf
13
+	patternArgument patternType = 1 << iota
14
+	patternCommand
15
+	patternOption
16
+
17
+	// branch
18
+	patternRequired
19
+	patternOptionAL
20
+	patternOptionSSHORTCUT // Marker/placeholder for [options] shortcut.
21
+	patternOneOrMore
22
+	patternEither
23
+
24
+	patternLeaf = patternArgument +
25
+		patternCommand +
26
+		patternOption
27
+	patternBranch = patternRequired +
28
+		patternOptionAL +
29
+		patternOptionSSHORTCUT +
30
+		patternOneOrMore +
31
+		patternEither
32
+	patternAll     = patternLeaf + patternBranch
33
+	patternDefault = 0
34
+)
35
+
36
+func (pt patternType) String() string {
37
+	switch pt {
38
+	case patternArgument:
39
+		return "argument"
40
+	case patternCommand:
41
+		return "command"
42
+	case patternOption:
43
+		return "option"
44
+	case patternRequired:
45
+		return "required"
46
+	case patternOptionAL:
47
+		return "optional"
48
+	case patternOptionSSHORTCUT:
49
+		return "optionsshortcut"
50
+	case patternOneOrMore:
51
+		return "oneormore"
52
+	case patternEither:
53
+		return "either"
54
+	case patternLeaf:
55
+		return "leaf"
56
+	case patternBranch:
57
+		return "branch"
58
+	case patternAll:
59
+		return "all"
60
+	case patternDefault:
61
+		return "default"
62
+	}
63
+	return ""
64
+}
65
+
66
+type pattern struct {
67
+	t patternType
68
+
69
+	children patternList
70
+
71
+	name  string
72
+	value interface{}
73
+
74
+	short    string
75
+	long     string
76
+	argcount int
77
+}
78
+
79
+type patternList []*pattern
80
+
81
+func newBranchPattern(t patternType, pl ...*pattern) *pattern {
82
+	var p pattern
83
+	p.t = t
84
+	p.children = make(patternList, len(pl))
85
+	copy(p.children, pl)
86
+	return &p
87
+}
88
+
89
+func newRequired(pl ...*pattern) *pattern {
90
+	return newBranchPattern(patternRequired, pl...)
91
+}
92
+
93
+func newEither(pl ...*pattern) *pattern {
94
+	return newBranchPattern(patternEither, pl...)
95
+}
96
+
97
+func newOneOrMore(pl ...*pattern) *pattern {
98
+	return newBranchPattern(patternOneOrMore, pl...)
99
+}
100
+
101
+func newOptional(pl ...*pattern) *pattern {
102
+	return newBranchPattern(patternOptionAL, pl...)
103
+}
104
+
105
+func newOptionsShortcut() *pattern {
106
+	var p pattern
107
+	p.t = patternOptionSSHORTCUT
108
+	return &p
109
+}
110
+
111
+func newLeafPattern(t patternType, name string, value interface{}) *pattern {
112
+	// default: value=nil
113
+	var p pattern
114
+	p.t = t
115
+	p.name = name
116
+	p.value = value
117
+	return &p
118
+}
119
+
120
+func newArgument(name string, value interface{}) *pattern {
121
+	// default: value=nil
122
+	return newLeafPattern(patternArgument, name, value)
123
+}
124
+
125
+func newCommand(name string, value interface{}) *pattern {
126
+	// default: value=false
127
+	var p pattern
128
+	p.t = patternCommand
129
+	p.name = name
130
+	p.value = value
131
+	return &p
132
+}
133
+
134
+func newOption(short, long string, argcount int, value interface{}) *pattern {
135
+	// default: "", "", 0, false
136
+	var p pattern
137
+	p.t = patternOption
138
+	p.short = short
139
+	p.long = long
140
+	if long != "" {
141
+		p.name = long
142
+	} else {
143
+		p.name = short
144
+	}
145
+	p.argcount = argcount
146
+	if value == false && argcount > 0 {
147
+		p.value = nil
148
+	} else {
149
+		p.value = value
150
+	}
151
+	return &p
152
+}
153
+
154
+func (p *pattern) flat(types patternType) (patternList, error) {
155
+	if p.t&patternLeaf != 0 {
156
+		if types == patternDefault {
157
+			types = patternAll
158
+		}
159
+		if p.t&types != 0 {
160
+			return patternList{p}, nil
161
+		}
162
+		return patternList{}, nil
163
+	}
164
+
165
+	if p.t&patternBranch != 0 {
166
+		if p.t&types != 0 {
167
+			return patternList{p}, nil
168
+		}
169
+		result := patternList{}
170
+		for _, child := range p.children {
171
+			childFlat, err := child.flat(types)
172
+			if err != nil {
173
+				return nil, err
174
+			}
175
+			result = append(result, childFlat...)
176
+		}
177
+		return result, nil
178
+	}
179
+	return nil, newError("unknown pattern type: %d, %d", p.t, types)
180
+}
181
+
182
+func (p *pattern) fix() error {
183
+	err := p.fixIdentities(nil)
184
+	if err != nil {
185
+		return err
186
+	}
187
+	p.fixRepeatingArguments()
188
+	return nil
189
+}
190
+
191
+func (p *pattern) fixIdentities(uniq patternList) error {
192
+	// Make pattern-tree tips point to same object if they are equal.
193
+	if p.t&patternBranch == 0 {
194
+		return nil
195
+	}
196
+	if uniq == nil {
197
+		pFlat, err := p.flat(patternDefault)
198
+		if err != nil {
199
+			return err
200
+		}
201
+		uniq = pFlat.unique()
202
+	}
203
+	for i, child := range p.children {
204
+		if child.t&patternBranch == 0 {
205
+			ind, err := uniq.index(child)
206
+			if err != nil {
207
+				return err
208
+			}
209
+			p.children[i] = uniq[ind]
210
+		} else {
211
+			err := child.fixIdentities(uniq)
212
+			if err != nil {
213
+				return err
214
+			}
215
+		}
216
+	}
217
+	return nil
218
+}
219
+
220
+func (p *pattern) fixRepeatingArguments() {
221
+	// Fix elements that should accumulate/increment values.
222
+	var either []patternList
223
+
224
+	for _, child := range p.transform().children {
225
+		either = append(either, child.children)
226
+	}
227
+	for _, cas := range either {
228
+		casMultiple := patternList{}
229
+		for _, e := range cas {
230
+			if cas.count(e) > 1 {
231
+				casMultiple = append(casMultiple, e)
232
+			}
233
+		}
234
+		for _, e := range casMultiple {
235
+			if e.t == patternArgument || e.t == patternOption && e.argcount > 0 {
236
+				switch e.value.(type) {
237
+				case string:
238
+					e.value = strings.Fields(e.value.(string))
239
+				case []string:
240
+				default:
241
+					e.value = []string{}
242
+				}
243
+			}
244
+			if e.t == patternCommand || e.t == patternOption && e.argcount == 0 {
245
+				e.value = 0
246
+			}
247
+		}
248
+	}
249
+}
250
+
251
+func (p *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) {
252
+	if collected == nil {
253
+		collected = &patternList{}
254
+	}
255
+	if p.t&patternRequired != 0 {
256
+		l := left
257
+		c := collected
258
+		for _, p := range p.children {
259
+			var matched bool
260
+			matched, l, c = p.match(l, c)
261
+			if !matched {
262
+				return false, left, collected
263
+			}
264
+		}
265
+		return true, l, c
266
+	} else if p.t&patternOptionAL != 0 || p.t&patternOptionSSHORTCUT != 0 {
267
+		for _, p := range p.children {
268
+			_, left, collected = p.match(left, collected)
269
+		}
270
+		return true, left, collected
271
+	} else if p.t&patternOneOrMore != 0 {
272
+		if len(p.children) != 1 {
273
+			panic("OneOrMore.match(): assert len(p.children) == 1")
274
+		}
275
+		l := left
276
+		c := collected
277
+		var lAlt *patternList
278
+		matched := true
279
+		times := 0
280
+		for matched {
281
+			// could it be that something didn't match but changed l or c?
282
+			matched, l, c = p.children[0].match(l, c)
283
+			if matched {
284
+				times++
285
+			}
286
+			if lAlt == l {
287
+				break
288
+			}
289
+			lAlt = l
290
+		}
291
+		if times >= 1 {
292
+			return true, l, c
293
+		}
294
+		return false, left, collected
295
+	} else if p.t&patternEither != 0 {
296
+		type outcomeStruct struct {
297
+			matched   bool
298
+			left      *patternList
299
+			collected *patternList
300
+			length    int
301
+		}
302
+		outcomes := []outcomeStruct{}
303
+		for _, p := range p.children {
304
+			matched, l, c := p.match(left, collected)
305
+			outcome := outcomeStruct{matched, l, c, len(*l)}
306
+			if matched {
307
+				outcomes = append(outcomes, outcome)
308
+			}
309
+		}
310
+		if len(outcomes) > 0 {
311
+			minLen := outcomes[0].length
312
+			minIndex := 0
313
+			for i, v := range outcomes {
314
+				if v.length < minLen {
315
+					minIndex = i
316
+				}
317
+			}
318
+			return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected
319
+		}
320
+		return false, left, collected
321
+	} else if p.t&patternLeaf != 0 {
322
+		pos, match := p.singleMatch(left)
323
+		var increment interface{}
324
+		if match == nil {
325
+			return false, left, collected
326
+		}
327
+		leftAlt := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:]))
328
+		copy(leftAlt, (*left)[:pos])
329
+		leftAlt = append(leftAlt, (*left)[pos+1:]...)
330
+		sameName := patternList{}
331
+		for _, a := range *collected {
332
+			if a.name == p.name {
333
+				sameName = append(sameName, a)
334
+			}
335
+		}
336
+
337
+		switch p.value.(type) {
338
+		case int, []string:
339
+			switch p.value.(type) {
340
+			case int:
341
+				increment = 1
342
+			case []string:
343
+				switch match.value.(type) {
344
+				case string:
345
+					increment = []string{match.value.(string)}
346
+				default:
347
+					increment = match.value
348
+				}
349
+			}
350
+			if len(sameName) == 0 {
351
+				match.value = increment
352
+				collectedMatch := make(patternList, len(*collected), len(*collected)+1)
353
+				copy(collectedMatch, *collected)
354
+				collectedMatch = append(collectedMatch, match)
355
+				return true, &leftAlt, &collectedMatch
356
+			}
357
+			switch sameName[0].value.(type) {
358
+			case int:
359
+				sameName[0].value = sameName[0].value.(int) + increment.(int)
360
+			case []string:
361
+				sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...)
362
+			}
363
+			return true, &leftAlt, collected
364
+		}
365
+		collectedMatch := make(patternList, len(*collected), len(*collected)+1)
366
+		copy(collectedMatch, *collected)
367
+		collectedMatch = append(collectedMatch, match)
368
+		return true, &leftAlt, &collectedMatch
369
+	}
370
+	panic("unmatched type")
371
+}
372
+
373
+func (p *pattern) singleMatch(left *patternList) (int, *pattern) {
374
+	if p.t&patternArgument != 0 {
375
+		for n, pat := range *left {
376
+			if pat.t&patternArgument != 0 {
377
+				return n, newArgument(p.name, pat.value)
378
+			}
379
+		}
380
+		return -1, nil
381
+	} else if p.t&patternCommand != 0 {
382
+		for n, pat := range *left {
383
+			if pat.t&patternArgument != 0 {
384
+				if pat.value == p.name {
385
+					return n, newCommand(p.name, true)
386
+				}
387
+				break
388
+			}
389
+		}
390
+		return -1, nil
391
+	} else if p.t&patternOption != 0 {
392
+		for n, pat := range *left {
393
+			if p.name == pat.name {
394
+				return n, pat
395
+			}
396
+		}
397
+		return -1, nil
398
+	}
399
+	panic("unmatched type")
400
+}
401
+
402
+func (p *pattern) String() string {
403
+	if p.t&patternOption != 0 {
404
+		return fmt.Sprintf("%s(%s, %s, %d, %+v)", p.t, p.short, p.long, p.argcount, p.value)
405
+	} else if p.t&patternLeaf != 0 {
406
+		return fmt.Sprintf("%s(%s, %+v)", p.t, p.name, p.value)
407
+	} else if p.t&patternBranch != 0 {
408
+		result := ""
409
+		for i, child := range p.children {
410
+			if i > 0 {
411
+				result += ", "
412
+			}
413
+			result += child.String()
414
+		}
415
+		return fmt.Sprintf("%s(%s)", p.t, result)
416
+	}
417
+	panic("unmatched type")
418
+}
419
+
420
+func (p *pattern) transform() *pattern {
421
+	/*
422
+		Expand pattern into an (almost) equivalent one, but with single Either.
423
+
424
+		Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
425
+		Quirks: [-a] => (-a), (-a...) => (-a -a)
426
+	*/
427
+	result := []patternList{}
428
+	groups := []patternList{patternList{p}}
429
+	parents := patternRequired +
430
+		patternOptionAL +
431
+		patternOptionSSHORTCUT +
432
+		patternEither +
433
+		patternOneOrMore
434
+	for len(groups) > 0 {
435
+		children := groups[0]
436
+		groups = groups[1:]
437
+		var child *pattern
438
+		for _, c := range children {
439
+			if c.t&parents != 0 {
440
+				child = c
441
+				break
442
+			}
443
+		}
444
+		if child != nil {
445
+			children.remove(child)
446
+			if child.t&patternEither != 0 {
447
+				for _, c := range child.children {
448
+					r := patternList{}
449
+					r = append(r, c)
450
+					r = append(r, children...)
451
+					groups = append(groups, r)
452
+				}
453
+			} else if child.t&patternOneOrMore != 0 {
454
+				r := patternList{}
455
+				r = append(r, child.children.double()...)
456
+				r = append(r, children...)
457
+				groups = append(groups, r)
458
+			} else {
459
+				r := patternList{}
460
+				r = append(r, child.children...)
461
+				r = append(r, children...)
462
+				groups = append(groups, r)
463
+			}
464
+		} else {
465
+			result = append(result, children)
466
+		}
467
+	}
468
+	either := patternList{}
469
+	for _, e := range result {
470
+		either = append(either, newRequired(e...))
471
+	}
472
+	return newEither(either...)
473
+}
474
+
475
+func (p *pattern) eq(other *pattern) bool {
476
+	return reflect.DeepEqual(p, other)
477
+}
478
+
479
+func (pl patternList) unique() patternList {
480
+	table := make(map[string]bool)
481
+	result := patternList{}
482
+	for _, v := range pl {
483
+		if !table[v.String()] {
484
+			table[v.String()] = true
485
+			result = append(result, v)
486
+		}
487
+	}
488
+	return result
489
+}
490
+
491
+func (pl patternList) index(p *pattern) (int, error) {
492
+	for i, c := range pl {
493
+		if c.eq(p) {
494
+			return i, nil
495
+		}
496
+	}
497
+	return -1, newError("%s not in list", p)
498
+}
499
+
500
+func (pl patternList) count(p *pattern) int {
501
+	count := 0
502
+	for _, c := range pl {
503
+		if c.eq(p) {
504
+			count++
505
+		}
506
+	}
507
+	return count
508
+}
509
+
510
+func (pl patternList) diff(l patternList) patternList {
511
+	lAlt := make(patternList, len(l))
512
+	copy(lAlt, l)
513
+	result := make(patternList, 0, len(pl))
514
+	for _, v := range pl {
515
+		if v != nil {
516
+			match := false
517
+			for i, w := range lAlt {
518
+				if w.eq(v) {
519
+					match = true
520
+					lAlt[i] = nil
521
+					break
522
+				}
523
+			}
524
+			if match == false {
525
+				result = append(result, v)
526
+			}
527
+		}
528
+	}
529
+	return result
530
+}
531
+
532
+func (pl patternList) double() patternList {
533
+	l := len(pl)
534
+	result := make(patternList, l*2)
535
+	copy(result, pl)
536
+	copy(result[l:2*l], pl)
537
+	return result
538
+}
539
+
540
+func (pl *patternList) remove(p *pattern) {
541
+	(*pl) = pl.diff(patternList{p})
542
+}
543
+
544
+func (pl patternList) dictionary() map[string]interface{} {
545
+	dict := make(map[string]interface{})
546
+	for _, a := range pl {
547
+		dict[a.name] = a.value
548
+	}
549
+	return dict
550
+}

+ 9
- 0
vendor/github.com/docopt/docopt-go/test_golang.docopt View File

@@ -0,0 +1,9 @@
1
+r"""usage: prog [NAME_-2]..."""
2
+$ prog 10 20
3
+{"NAME_-2": ["10", "20"]}
4
+
5
+$ prog 10
6
+{"NAME_-2": ["10"]}
7
+
8
+$ prog
9
+{"NAME_-2": []}

+ 957
- 0
vendor/github.com/docopt/docopt-go/testcases.docopt View File

@@ -0,0 +1,957 @@
1
+r"""Usage: prog
2
+
3
+"""
4
+$ prog
5
+{}
6
+
7
+$ prog --xxx
8
+"user-error"
9
+
10
+
11
+r"""Usage: prog [options]
12
+
13
+Options: -a  All.
14
+
15
+"""
16
+$ prog
17
+{"-a": false}
18
+
19
+$ prog -a
20
+{"-a": true}
21
+
22
+$ prog -x
23
+"user-error"
24
+
25
+
26
+r"""Usage: prog [options]
27
+
28
+Options: --all  All.
29
+
30
+"""
31
+$ prog
32
+{"--all": false}
33
+
34
+$ prog --all
35
+{"--all": true}
36
+
37
+$ prog --xxx
38
+"user-error"
39
+
40
+
41
+r"""Usage: prog [options]
42
+
43
+Options: -v, --verbose  Verbose.
44
+
45
+"""
46
+$ prog --verbose
47
+{"--verbose": true}
48
+
49
+$ prog --ver
50
+{"--verbose": true}
51
+
52
+$ prog -v
53
+{"--verbose": true}
54
+
55
+
56
+r"""Usage: prog [options]
57
+
58
+Options: -p PATH
59
+
60
+"""
61
+$ prog -p home/
62
+{"-p": "home/"}
63
+
64
+$ prog -phome/
65
+{"-p": "home/"}
66
+
67
+$ prog -p
68
+"user-error"
69
+
70
+
71
+r"""Usage: prog [options]
72
+
73
+Options: --path <path>
74
+
75
+"""
76
+$ prog --path home/
77
+{"--path": "home/"}
78
+
79
+$ prog --path=home/
80
+{"--path": "home/"}
81
+
82
+$ prog --pa home/
83
+{"--path": "home/"}
84
+
85
+$ prog --pa=home/
86
+{"--path": "home/"}
87
+
88
+$ prog --path
89
+"user-error"
90
+
91
+
92
+r"""Usage: prog [options]
93
+
94
+Options: -p PATH, --path=<path>  Path to files.
95
+
96
+"""
97
+$ prog -proot
98
+{"--path": "root"}
99
+
100
+
101
+r"""Usage: prog [options]
102
+
103
+Options:    -p --path PATH  Path to files.
104
+
105
+"""
106
+$ prog -p root
107
+{"--path": "root"}
108
+
109
+$ prog --path root
110
+{"--path": "root"}
111
+
112
+
113
+r"""Usage: prog [options]
114
+
115
+Options:
116
+ -p PATH  Path to files [default: ./]
117
+
118
+"""
119
+$ prog
120
+{"-p": "./"}
121
+
122
+$ prog -phome
123
+{"-p": "home"}
124
+
125
+
126
+r"""UsAgE: prog [options]
127
+
128
+OpTiOnS: --path=<files>  Path to files
129
+                [dEfAuLt: /root]
130
+
131
+"""
132
+$ prog
133
+{"--path": "/root"}
134
+
135
+$ prog --path=home
136
+{"--path": "home"}
137
+
138
+
139
+r"""usage: prog [options]
140
+
141
+options:
142
+    -a        Add
143
+    -r        Remote
144
+    -m <msg>  Message
145
+
146
+"""
147
+$ prog -a -r -m Hello
148
+{"-a": true,
149
+ "-r": true,
150
+ "-m": "Hello"}
151
+
152
+$ prog -armyourass
153
+{"-a": true,
154
+ "-r": true,
155
+ "-m": "yourass"}
156
+
157
+$ prog -a -r
158
+{"-a": true,
159
+ "-r": true,
160
+ "-m": null}
161
+
162
+
163
+r"""Usage: prog [options]
164
+
165
+Options: --version
166
+         --verbose
167
+
168
+"""
169
+$ prog --version
170
+{"--version": true,
171
+ "--verbose": false}
172
+
173
+$ prog --verbose
174
+{"--version": false,
175
+ "--verbose": true}
176
+
177
+$ prog --ver
178
+"user-error"
179
+
180
+$ prog --verb
181
+{"--version": false,
182
+ "--verbose": true}
183
+
184
+
185
+r"""usage: prog [-a -r -m <msg>]
186
+
187
+options:
188
+ -a        Add
189
+ -r        Remote
190
+ -m <msg>  Message
191
+
192
+"""
193
+$ prog -armyourass
194
+{"-a": true,
195
+ "-r": true,
196
+ "-m": "yourass"}
197
+
198
+
199
+r"""usage: prog [-armmsg]
200
+
201
+options: -a        Add
202
+         -r        Remote
203
+         -m <msg>  Message
204
+
205
+"""
206
+$ prog -a -r -m Hello
207
+{"-a": true,
208
+ "-r": true,
209
+ "-m": "Hello"}
210
+
211
+
212
+r"""usage: prog -a -b
213
+
214
+options:
215
+ -a
216
+ -b
217
+
218
+"""
219
+$ prog -a -b
220
+{"-a": true, "-b": true}
221
+
222
+$ prog -b -a
223
+{"-a": true, "-b": true}
224
+
225
+$ prog -a
226
+"user-error"
227
+
228
+$ prog
229
+"user-error"
230
+
231
+
232
+r"""usage: prog (-a -b)
233
+
234
+options: -a
235
+         -b
236
+
237
+"""
238
+$ prog -a -b
239
+{"-a": true, "-b": true}
240
+
241
+$ prog -b -a
242
+{"-a": true, "-b": true}
243
+
244
+$ prog -a
245
+"user-error"
246
+
247
+$ prog
248
+"user-error"
249
+
250
+
251
+r"""usage: prog [-a] -b
252
+
253
+options: -a
254
+ -b
255
+
256
+"""
257
+$ prog -a -b
258
+{"-a": true, "-b": true}
259
+
260
+$ prog -b -a
261
+{"-a": true, "-b": true}
262
+
263
+$ prog -a
264
+"user-error"
265
+
266
+$ prog -b
267
+{"-a": false, "-b": true}
268
+
269
+$ prog
270
+"user-error"
271
+
272
+
273
+r"""usage: prog [(-a -b)]
274
+
275
+options: -a
276
+         -b
277
+
278
+"""
279
+$ prog -a -b
280
+{"-a": true, "-b": true}
281
+
282
+$ prog -b -a
283
+{"-a": true, "-b": true}
284
+
285
+$ prog -a
286
+"user-error"
287
+
288
+$ prog -b
289
+"user-error"
290
+
291
+$ prog
292
+{"-a": false, "-b": false}
293
+
294
+
295
+r"""usage: prog (-a|-b)
296
+
297
+options: -a
298
+         -b
299
+
300
+"""
301
+$ prog -a -b
302
+"user-error"
303
+
304
+$ prog
305
+"user-error"
306
+
307
+$ prog -a
308
+{"-a": true, "-b": false}
309
+
310
+$ prog -b
311
+{"-a": false, "-b": true}
312
+
313
+
314
+r"""usage: prog [ -a | -b ]
315
+
316
+options: -a
317
+         -b
318
+
319
+"""
320
+$ prog -a -b
321
+"user-error"
322
+
323
+$ prog
324
+{"-a": false, "-b": false}
325
+
326
+$ prog -a
327
+{"-a": true, "-b": false}
328
+
329
+$ prog -b
330
+{"-a": false, "-b": true}
331
+
332
+
333
+r"""usage: prog <arg>"""
334
+$ prog 10
335
+{"<arg>": "10"}
336
+
337
+$ prog 10 20
338
+"user-error"
339
+
340
+$ prog
341
+"user-error"
342
+
343
+
344
+r"""usage: prog [<arg>]"""
345
+$ prog 10
346
+{"<arg>": "10"}
347
+
348
+$ prog 10 20
349
+"user-error"
350
+
351
+$ prog
352
+{"<arg>": null}
353
+
354
+
355
+r"""usage: prog <kind> <name> <type>"""
356
+$ prog 10 20 40
357
+{"<kind>": "10", "<name>": "20", "<type>": "40"}
358
+
359
+$ prog 10 20
360
+"user-error"
361
+
362
+$ prog
363
+"user-error"
364
+
365
+
366
+r"""usage: prog <kind> [<name> <type>]"""
367
+$ prog 10 20 40
368
+{"<kind>": "10", "<name>": "20", "<type>": "40"}
369
+
370
+$ prog 10 20
371
+{"<kind>": "10", "<name>": "20", "<type>": null}
372
+
373
+$ prog
374
+"user-error"
375
+
376
+
377
+r"""usage: prog [<kind> | <name> <type>]"""
378
+$ prog 10 20 40
379
+"user-error"
380
+
381
+$ prog 20 40
382
+{"<kind>": null, "<name>": "20", "<type>": "40"}
383
+
384
+$ prog
385
+{"<kind>": null, "<name>": null, "<type>": null}
386
+
387
+
388
+r"""usage: prog (<kind> --all | <name>)
389
+
390
+options:
391
+ --all
392
+
393
+"""
394
+$ prog 10 --all
395
+{"<kind>": "10", "--all": true, "<name>": null}
396
+
397
+$ prog 10
398
+{"<kind>": null, "--all": false, "<name>": "10"}
399
+
400
+$ prog
401
+"user-error"
402
+
403
+
404
+r"""usage: prog [<name> <name>]"""
405
+$ prog 10 20
406
+{"<name>": ["10", "20"]}
407
+
408
+$ prog 10
409
+{"<name>": ["10"]}
410
+
411
+$ prog
412
+{"<name>": []}
413
+
414
+
415
+r"""usage: prog [(<name> <name>)]"""
416
+$ prog 10 20
417
+{"<name>": ["10", "20"]}
418
+
419
+$ prog 10
420
+"user-error"
421
+
422
+$ prog
423
+{"<name>": []}
424
+
425
+
426
+r"""usage: prog NAME..."""
427
+$ prog 10 20
428
+{"NAME": ["10", "20"]}
429
+
430
+$ prog 10
431
+{"NAME": ["10"]}
432
+
433
+$ prog
434
+"user-error"
435
+
436
+
437
+r"""usage: prog [NAME]..."""
438
+$ prog 10 20
439
+{"NAME": ["10", "20"]}
440
+
441
+$ prog 10
442
+{"NAME": ["10"]}
443
+
444
+$ prog
445
+{"NAME": []}
446
+
447
+
448
+r"""usage: prog [NAME...]"""
449
+$ prog 10 20
450
+{"NAME": ["10", "20"]}
451
+
452
+$ prog 10
453
+{"NAME": ["10"]}
454
+
455
+$ prog
456
+{"NAME": []}
457
+
458
+
459
+r"""usage: prog [NAME [NAME ...]]"""
460
+$ prog 10 20
461
+{"NAME": ["10", "20"]}
462
+
463
+$ prog 10
464
+{"NAME": ["10"]}
465
+
466
+$ prog
467
+{"NAME": []}
468
+
469
+
470
+r"""usage: prog (NAME | --foo NAME)
471
+
472
+options: --foo
473
+
474
+"""
475
+$ prog 10
476
+{"NAME": "10", "--foo": false}
477
+
478
+$ prog --foo 10
479
+{"NAME": "10", "--foo": true}
480
+
481
+$ prog --foo=10
482
+"user-error"
483
+
484
+
485
+r"""usage: prog (NAME | --foo) [--bar | NAME]
486
+
487
+options: --foo
488
+options: --bar
489
+
490
+"""
491
+$ prog 10
492
+{"NAME": ["10"], "--foo": false, "--bar": false}
493
+
494
+$ prog 10 20
495
+{"NAME": ["10", "20"], "--foo": false, "--bar": false}
496
+
497
+$ prog --foo --bar
498
+{"NAME": [], "--foo": true, "--bar": true}
499
+
500
+
501
+r"""Naval Fate.
502
+
503
+Usage:
504
+  prog ship new <name>...
505
+  prog ship [<name>] move <x> <y> [--speed=<kn>]
506
+  prog ship shoot <x> <y>
507
+  prog mine (set|remove) <x> <y> [--moored|--drifting]
508
+  prog -h | --help
509
+  prog --version
510
+
511
+Options:
512
+  -h --help     Show this screen.
513
+  --version     Show version.
514
+  --speed=<kn>  Speed in knots [default: 10].
515
+  --moored      Mored (anchored) mine.
516
+  --drifting    Drifting mine.
517
+
518
+"""
519
+$ prog ship Guardian move 150 300 --speed=20
520
+{"--drifting": false,
521
+ "--help": false,
522
+ "--moored": false,
523
+ "--speed": "20",
524
+ "--version": false,
525
+ "<name>": ["Guardian"],
526
+ "<x>": "150",
527
+ "<y>": "300",
528
+ "mine": false,
529
+ "move": true,
530
+ "new": false,
531
+ "remove": false,
532
+ "set": false,
533
+ "ship": true,
534
+ "shoot": false}
535
+
536
+
537
+r"""usage: prog --hello"""
538
+$ prog --hello
539
+{"--hello": true}
540
+
541
+
542
+r"""usage: prog [--hello=<world>]"""
543
+$ prog
544
+{"--hello": null}
545
+
546
+$ prog --hello wrld
547
+{"--hello": "wrld"}
548
+
549
+
550
+r"""usage: prog [-o]"""
551
+$ prog
552
+{"-o": false}
553
+
554
+$ prog -o
555
+{"-o": true}
556
+
557
+
558
+r"""usage: prog [-opr]"""
559
+$ prog -op
560
+{"-o": true, "-p": true, "-r": false}
561
+
562
+
563
+r"""usage: prog --aabb | --aa"""
564
+$ prog --aa
565
+{"--aabb": false, "--aa": true}
566
+
567
+$ prog --a
568
+"user-error"  # not a unique prefix
569
+
570
+#
571
+# Counting number of flags
572
+#
573
+
574
+r"""Usage: prog -v"""
575
+$ prog -v
576
+{"-v": true}
577
+
578
+
579
+r"""Usage: prog [-v -v]"""
580
+$ prog
581
+{"-v": 0}
582
+
583
+$ prog -v
584
+{"-v": 1}
585
+
586
+$ prog -vv
587
+{"-v": 2}
588
+
589
+
590
+r"""Usage: prog -v ..."""
591
+$ prog
592
+"user-error"
593
+
594
+$ prog -v
595
+{"-v": 1}
596
+
597
+$ prog -vv
598
+{"-v": 2}
599
+
600
+$ prog -vvvvvv
601
+{"-v": 6}
602
+
603
+
604
+r"""Usage: prog [-v | -vv | -vvv]
605
+
606
+This one is probably most readable user-friednly variant.
607
+
608
+"""
609
+$ prog
610
+{"-v": 0}
611
+
612
+$ prog -v
613
+{"-v": 1}
614
+
615
+$ prog -vv
616
+{"-v": 2}
617
+
618
+$ prog -vvvv
619
+"user-error"
620
+
621
+
622
+r"""usage: prog [--ver --ver]"""
623
+$ prog --ver --ver
624
+{"--ver": 2}
625
+
626
+
627
+#
628
+# Counting commands
629
+#
630
+
631
+r"""usage: prog [go]"""
632
+$ prog go
633
+{"go": true}
634
+
635
+
636
+r"""usage: prog [go go]"""
637
+$ prog
638
+{"go": 0}
639
+
640
+$ prog go
641
+{"go": 1}
642
+
643
+$ prog go go
644
+{"go": 2}
645
+
646
+$ prog go go go
647
+"user-error"
648
+
649
+r"""usage: prog go..."""
650
+$ prog go go go go go
651
+{"go": 5}
652
+
653
+#
654
+# [options] does not include options from usage-pattern
655
+#
656
+r"""usage: prog [options] [-a]
657
+
658
+options: -a
659
+         -b
660
+"""
661
+$ prog -a
662
+{"-a": true, "-b": false}
663
+
664
+$ prog -aa
665
+"user-error"
666
+
667
+#
668
+# Test [options] shourtcut
669
+#
670
+
671
+r"""Usage: prog [options] A
672
+Options:
673
+    -q  Be quiet
674
+    -v  Be verbose.
675
+
676
+"""
677
+$ prog arg
678
+{"A": "arg", "-v": false, "-q": false}
679
+
680
+$ prog -v arg
681
+{"A": "arg", "-v": true, "-q": false}
682
+
683
+$ prog -q arg
684
+{"A": "arg", "-v": false, "-q": true}
685
+
686
+#
687
+# Test single dash
688
+#
689
+
690
+r"""usage: prog [-]"""
691
+
692
+$ prog -
693
+{"-": true}
694
+
695
+$ prog
696
+{"-": false}
697
+
698
+#
699
+# If argument is repeated, its value should always be a list
700
+#
701
+
702
+r"""usage: prog [NAME [NAME ...]]"""
703
+
704
+$ prog a b
705
+{"NAME": ["a", "b"]}
706
+
707
+$ prog
708
+{"NAME": []}
709
+
710
+#
711
+# Option's argument defaults to null/None
712
+#
713
+
714
+r"""usage: prog [options]
715
+options:
716
+ -a        Add
717
+ -m <msg>  Message
718
+
719
+"""
720
+$ prog -a
721
+{"-m": null, "-a": true}
722
+
723
+#
724
+# Test options without description
725
+#
726
+
727
+r"""usage: prog --hello"""
728
+$ prog --hello
729
+{"--hello": true}
730
+
731
+r"""usage: prog [--hello=<world>]"""
732
+$ prog
733
+{"--hello": null}
734
+
735
+$ prog --hello wrld
736
+{"--hello": "wrld"}
737
+
738
+r"""usage: prog [-o]"""
739
+$ prog
740
+{"-o": false}
741
+
742
+$ prog -o
743
+{"-o": true}
744
+
745
+r"""usage: prog [-opr]"""
746
+$ prog -op
747
+{"-o": true, "-p": true, "-r": false}
748
+
749
+r"""usage: git [-v | --verbose]"""
750
+$ prog -v
751
+{"-v": true, "--verbose": false}
752
+
753
+r"""usage: git remote [-v | --verbose]"""
754
+$ prog remote -v
755
+{"remote": true, "-v": true, "--verbose": false}
756
+
757
+#
758
+# Test empty usage pattern
759
+#
760
+
761
+r"""usage: prog"""
762
+$ prog
763
+{}
764
+
765
+r"""usage: prog
766
+           prog <a> <b>
767
+"""
768
+$ prog 1 2
769
+{"<a>": "1", "<b>": "2"}
770
+
771
+$ prog
772
+{"<a>": null, "<b>": null}
773
+
774
+r"""usage: prog <a> <b>
775
+           prog
776
+"""
777
+$ prog
778
+{"<a>": null, "<b>": null}
779
+
780
+#
781
+# Option's argument should not capture default value from usage pattern
782
+#
783
+
784
+r"""usage: prog [--file=<f>]"""
785
+$ prog
786
+{"--file": null}
787
+
788
+r"""usage: prog [--file=<f>]
789
+
790
+options: --file <a>
791
+
792
+"""
793
+$ prog
794
+{"--file": null}
795
+
796
+r"""Usage: prog [-a <host:port>]
797
+
798
+Options: -a, --address <host:port>  TCP address [default: localhost:6283].
799
+
800
+"""
801
+$ prog
802
+{"--address": "localhost:6283"}
803
+
804
+#
805
+# If option with argument could be repeated,
806
+# its arguments should be accumulated into a list
807
+#
808
+
809
+r"""usage: prog --long=<arg> ..."""
810
+
811
+$ prog --long one
812
+{"--long": ["one"]}
813
+
814
+$ prog --long one --long two
815
+{"--long": ["one", "two"]}
816
+
817
+#
818
+# Test multiple elements repeated at once
819
+#
820
+
821
+r"""usage: prog (go <direction> --speed=<km/h>)..."""
822
+$ prog  go left --speed=5  go right --speed=9
823
+{"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
824
+
825
+#
826
+# Required options should work with option shortcut
827
+#
828
+
829
+r"""usage: prog [options] -a
830
+
831
+options: -a
832
+
833
+"""
834
+$ prog -a
835
+{"-a": true}
836
+
837
+#
838
+# If option could be repeated its defaults should be split into a list
839
+#
840
+
841
+r"""usage: prog [-o <o>]...
842
+
843
+options: -o <o>  [default: x]
844
+
845
+"""
846
+$ prog -o this -o that
847
+{"-o": ["this", "that"]}
848
+
849
+$ prog
850
+{"-o": ["x"]}
851
+
852
+r"""usage: prog [-o <o>]...
853
+
854
+options: -o <o>  [default: x y]
855
+
856
+"""
857
+$ prog -o this
858
+{"-o": ["this"]}
859
+
860
+$ prog
861
+{"-o": ["x", "y"]}
862
+
863
+#
864
+# Test stacked option's argument
865
+#
866
+
867
+r"""usage: prog -pPATH
868
+
869
+options: -p PATH
870
+
871
+"""
872
+$ prog -pHOME
873
+{"-p": "HOME"}
874
+
875
+#
876
+# Issue 56: Repeated mutually exclusive args give nested lists sometimes
877
+#
878
+
879
+r"""Usage: foo (--xx=x|--yy=y)..."""
880
+$ prog --xx=1 --yy=2
881
+{"--xx": ["1"], "--yy": ["2"]}
882
+
883
+#
884
+# POSIXly correct tokenization
885
+#
886
+
887
+r"""usage: prog [<input file>]"""
888
+$ prog f.txt
889
+{"<input file>": "f.txt"}
890
+
891
+r"""usage: prog [--input=<file name>]..."""
892
+$ prog --input a.txt --input=b.txt
893
+{"--input": ["a.txt", "b.txt"]}
894
+
895
+#
896
+# Issue 85: `[options]` shourtcut with multiple subcommands
897
+#
898
+
899
+r"""usage: prog good [options]
900
+           prog fail [options]
901
+
902
+options: --loglevel=N
903
+
904
+"""
905
+$ prog fail --loglevel 5
906
+{"--loglevel": "5", "fail": true, "good": false}
907
+
908
+#
909
+# Usage-section syntax
910
+#
911
+
912
+r"""usage:prog --foo"""
913
+$ prog --foo
914
+{"--foo": true}
915
+
916
+r"""PROGRAM USAGE: prog --foo"""
917
+$ prog --foo
918
+{"--foo": true}
919
+
920
+r"""Usage: prog --foo
921
+           prog --bar
922
+NOT PART OF SECTION"""
923
+$ prog --foo
924
+{"--foo": true, "--bar": false}
925
+
926
+r"""Usage:
927
+ prog --foo
928
+ prog --bar
929
+
930
+NOT PART OF SECTION"""
931
+$ prog --foo
932
+{"--foo": true, "--bar": false}
933
+
934
+r"""Usage:
935
+ prog --foo
936
+ prog --bar
937
+NOT PART OF SECTION"""
938
+$ prog --foo
939
+{"--foo": true, "--bar": false}
940
+
941
+#
942
+# Options-section syntax
943
+#
944
+
945
+r"""Usage: prog [options]
946
+
947
+global options: --foo
948
+local options: --baz
949
+               --bar
950
+other options:
951
+ --egg
952
+ --spam
953
+-not-an-option-
954
+
955
+"""
956
+$ prog --baz --egg
957
+{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}

+ 126
- 0
vendor/github.com/docopt/docopt-go/token.go View File

@@ -0,0 +1,126 @@
1
+package docopt
2
+
3
+import (
4
+	"regexp"
5
+	"strings"
6
+	"unicode"
7
+)
8
+
9
+type tokenList struct {
10
+	tokens    []string
11
+	errorFunc func(string, ...interface{}) error
12
+	err       errorType
13
+}
14
+type token string
15
+
16
+func newTokenList(source []string, err errorType) *tokenList {
17
+	errorFunc := newError
18
+	if err == errorUser {
19
+		errorFunc = newUserError
20
+	} else if err == errorLanguage {
21
+		errorFunc = newLanguageError
22
+	}
23
+	return &tokenList{source, errorFunc, err}
24
+}
25
+
26
+func tokenListFromString(source string) *tokenList {
27
+	return newTokenList(strings.Fields(source), errorUser)
28
+}
29
+
30
+func tokenListFromPattern(source string) *tokenList {
31
+	p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`)
32
+	source = p.ReplaceAllString(source, ` $1 `)
33
+	p = regexp.MustCompile(`\s+|(\S*<.*?>)`)
34
+	split := p.Split(source, -1)
35
+	match := p.FindAllStringSubmatch(source, -1)
36
+	var result []string
37
+	l := len(split)
38
+	for i := 0; i < l; i++ {
39
+		if len(split[i]) > 0 {
40
+			result = append(result, split[i])
41
+		}
42
+		if i < l-1 && len(match[i][1]) > 0 {
43
+			result = append(result, match[i][1])
44
+		}
45
+	}
46
+	return newTokenList(result, errorLanguage)
47
+}
48
+
49
+func (t *token) eq(s string) bool {
50
+	if t == nil {
51
+		return false
52
+	}
53
+	return string(*t) == s
54
+}
55
+func (t *token) match(matchNil bool, tokenStrings ...string) bool {
56
+	if t == nil && matchNil {
57
+		return true
58
+	} else if t == nil && !matchNil {
59
+		return false
60
+	}
61
+
62
+	for _, tok := range tokenStrings {
63
+		if tok == string(*t) {
64
+			return true
65
+		}
66
+	}
67
+	return false
68
+}
69
+func (t *token) hasPrefix(prefix string) bool {
70
+	if t == nil {
71
+		return false
72
+	}
73
+	return strings.HasPrefix(string(*t), prefix)
74
+}
75
+func (t *token) hasSuffix(suffix string) bool {
76
+	if t == nil {
77
+		return false
78
+	}
79
+	return strings.HasSuffix(string(*t), suffix)
80
+}
81
+func (t *token) isUpper() bool {
82
+	if t == nil {
83
+		return false
84
+	}
85
+	return isStringUppercase(string(*t))
86
+}
87
+func (t *token) String() string {
88
+	if t == nil {
89
+		return ""
90
+	}
91
+	return string(*t)
92
+}
93
+
94
+func (tl *tokenList) current() *token {
95
+	if len(tl.tokens) > 0 {
96
+		return (*token)(&(tl.tokens[0]))
97
+	}
98
+	return nil
99
+}
100
+
101
+func (tl *tokenList) length() int {
102
+	return len(tl.tokens)
103
+}
104
+
105
+func (tl *tokenList) move() *token {
106
+	if len(tl.tokens) > 0 {
107
+		t := tl.tokens[0]
108
+		tl.tokens = tl.tokens[1:]
109
+		return (*token)(&t)
110
+	}
111
+	return nil
112
+}
113
+
114
+// returns true if all cased characters in the string are uppercase
115
+// and there are there is at least one cased charcter
116
+func isStringUppercase(s string) bool {
117
+	if strings.ToUpper(s) != s {
118
+		return false
119
+	}
120
+	for _, c := range []rune(s) {
121
+		if unicode.IsUpper(c) {
122
+			return true
123
+		}
124
+	}
125
+	return false
126
+}

+ 38
- 0
vendor/github.com/go-asn1-ber/asn1-ber/.travis.yml View File

@@ -0,0 +1,38 @@
1
+language: go
2
+matrix:
3
+    include:
4
+        - go: 1.2.x
5
+          env: GOOS=linux GOARCH=amd64
6
+        - go: 1.2.x
7
+          env: GOOS=linux GOARCH=386
8
+        - go: 1.2.x
9
+          env: GOOS=windows GOARCH=amd64
10
+        - go: 1.2.x
11
+          env: GOOS=windows GOARCH=386
12
+        - go: 1.3.x
13
+        - go: 1.4.x
14
+        - go: 1.5.x
15
+        - go: 1.6.x
16
+        - go: 1.7.x
17
+        - go: 1.8.x
18
+        - go: 1.9.x
19
+        - go: 1.10.x
20
+        - go: 1.11.x
21
+        - go: 1.12.x
22
+        - go: 1.13.x
23
+          env: GOOS=linux GOARCH=amd64
24
+        - go: 1.13.x
25
+          env: GOOS=linux GOARCH=386
26
+        - go: 1.13.x
27
+          env: GOOS=windows GOARCH=amd64
28
+        - go: 1.13.x
29
+          env: GOOS=windows GOARCH=386
30
+        - go: tip
31
+go_import_path: gopkg.in/asn-ber.v1
32
+install:
33
+    - go list -f '{{range .Imports}}{{.}} {{end}}' ./... | xargs go get -v
34
+    - go list -f '{{range .TestImports}}{{.}} {{end}}' ./... | xargs go get -v
35
+    - go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover
36
+    - go build -v ./...
37
+script:
38
+    - go test -v -cover ./... || go test -v ./...

+ 22
- 0
vendor/github.com/go-asn1-ber/asn1-ber/LICENSE View File

@@ -0,0 +1,22 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)
4
+Portions copyright (c) 2015-2016 go-asn1-ber Authors
5
+
6
+Permission is hereby granted, free of charge, to any person obtaining a copy
7
+of this software and associated documentation files (the "Software"), to deal
8
+in the Software without restriction, including without limitation the rights
9
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+copies of the Software, and to permit persons to whom the Software is
11
+furnished to do so, subject to the following conditions:
12
+
13
+The above copyright notice and this permission notice shall be included in all
14
+copies or substantial portions of the Software.
15
+
16
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+SOFTWARE.

+ 24
- 0
vendor/github.com/go-asn1-ber/asn1-ber/README.md View File

@@ -0,0 +1,24 @@
1
+[![GoDoc](https://godoc.org/gopkg.in/asn1-ber.v1?status.svg)](https://godoc.org/gopkg.in/asn1-ber.v1) [![Build Status](https://travis-ci.org/go-asn1-ber/asn1-ber.svg)](https://travis-ci.org/go-asn1-ber/asn1-ber)
2
+
3
+
4
+ASN1 BER Encoding / Decoding Library for the GO programming language.
5
+---------------------------------------------------------------------
6
+
7
+Required libraries: 
8
+   None
9
+
10
+Working:
11
+   Very basic encoding / decoding needed for LDAP protocol
12
+
13
+Tests Implemented:
14
+   A few
15
+
16
+TODO:
17
+   Fix all encoding / decoding to conform to ASN1 BER spec
18
+   Implement Tests / Benchmarks
19
+
20
+---
21
+
22
+The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
23
+The design is licensed under the Creative Commons 3.0 Attributions license.
24
+Read this article for more details: http://blog.golang.org/gopher

+ 512
- 0
vendor/github.com/go-asn1-ber/asn1-ber/ber.go View File

@@ -0,0 +1,512 @@
1
+package ber
2
+
3
+import (
4
+	"bytes"
5
+	"errors"
6
+	"fmt"
7
+	"io"
8
+	"math"
9
+	"os"
10
+	"reflect"
11
+)
12
+
13
+// MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for
14
+// no limit.
15
+var MaxPacketLengthBytes int64 = math.MaxInt32
16
+
17
+type Packet struct {
18
+	Identifier
19
+	Value       interface{}
20
+	ByteValue   []byte
21
+	Data        *bytes.Buffer
22
+	Children    []*Packet
23
+	Description string
24
+}
25
+
26
+type Identifier struct {
27
+	ClassType Class
28
+	TagType   Type
29
+	Tag       Tag
30
+}
31
+
32
+type Tag uint64
33
+
34
+const (
35
+	TagEOC              Tag = 0x00
36
+	TagBoolean          Tag = 0x01
37
+	TagInteger          Tag = 0x02
38
+	TagBitString        Tag = 0x03
39
+	TagOctetString      Tag = 0x04
40
+	TagNULL             Tag = 0x05
41
+	TagObjectIdentifier Tag = 0x06
42
+	TagObjectDescriptor Tag = 0x07
43
+	TagExternal         Tag = 0x08
44
+	TagRealFloat        Tag = 0x09
45
+	TagEnumerated       Tag = 0x0a
46
+	TagEmbeddedPDV      Tag = 0x0b
47
+	TagUTF8String       Tag = 0x0c
48
+	TagRelativeOID      Tag = 0x0d
49
+	TagSequence         Tag = 0x10
50
+	TagSet              Tag = 0x11
51
+	TagNumericString    Tag = 0x12
52
+	TagPrintableString  Tag = 0x13
53
+	TagT61String        Tag = 0x14
54
+	TagVideotexString   Tag = 0x15
55
+	TagIA5String        Tag = 0x16
56
+	TagUTCTime          Tag = 0x17
57
+	TagGeneralizedTime  Tag = 0x18
58
+	TagGraphicString    Tag = 0x19
59
+	TagVisibleString    Tag = 0x1a
60
+	TagGeneralString    Tag = 0x1b
61
+	TagUniversalString  Tag = 0x1c
62
+	TagCharacterString  Tag = 0x1d
63
+	TagBMPString        Tag = 0x1e
64
+	TagBitmask          Tag = 0x1f // xxx11111b
65
+
66
+	// HighTag indicates the start of a high-tag byte sequence
67
+	HighTag Tag = 0x1f // xxx11111b
68
+	// HighTagContinueBitmask indicates the high-tag byte sequence should continue
69
+	HighTagContinueBitmask Tag = 0x80 // 10000000b
70
+	// HighTagValueBitmask obtains the tag value from a high-tag byte sequence byte
71
+	HighTagValueBitmask Tag = 0x7f // 01111111b
72
+)
73
+
74
+const (
75
+	// LengthLongFormBitmask is the mask to apply to the length byte to see if a long-form byte sequence is used
76
+	LengthLongFormBitmask = 0x80
77
+	// LengthValueBitmask is the mask to apply to the length byte to get the number of bytes in the long-form byte sequence
78
+	LengthValueBitmask = 0x7f
79
+
80
+	// LengthIndefinite is returned from readLength to indicate an indefinite length
81
+	LengthIndefinite = -1
82
+)
83
+
84
+var tagMap = map[Tag]string{
85
+	TagEOC:              "EOC (End-of-Content)",
86
+	TagBoolean:          "Boolean",
87
+	TagInteger:          "Integer",
88
+	TagBitString:        "Bit String",
89
+	TagOctetString:      "Octet String",
90
+	TagNULL:             "NULL",
91
+	TagObjectIdentifier: "Object Identifier",
92
+	TagObjectDescriptor: "Object Descriptor",
93
+	TagExternal:         "External",
94
+	TagRealFloat:        "Real (float)",
95
+	TagEnumerated:       "Enumerated",
96
+	TagEmbeddedPDV:      "Embedded PDV",
97
+	TagUTF8String:       "UTF8 String",
98
+	TagRelativeOID:      "Relative-OID",
99
+	TagSequence:         "Sequence and Sequence of",
100
+	TagSet:              "Set and Set OF",
101
+	TagNumericString:    "Numeric String",
102
+	TagPrintableString:  "Printable String",
103
+	TagT61String:        "T61 String",
104
+	TagVideotexString:   "Videotex String",
105
+	TagIA5String:        "IA5 String",
106
+	TagUTCTime:          "UTC Time",
107
+	TagGeneralizedTime:  "Generalized Time",
108
+	TagGraphicString:    "Graphic String",
109
+	TagVisibleString:    "Visible String",
110
+	TagGeneralString:    "General String",
111
+	TagUniversalString:  "Universal String",
112
+	TagCharacterString:  "Character String",
113
+	TagBMPString:        "BMP String",
114
+}
115
+
116
+type Class uint8
117
+
118
+const (
119
+	ClassUniversal   Class = 0   // 00xxxxxxb
120
+	ClassApplication Class = 64  // 01xxxxxxb
121
+	ClassContext     Class = 128 // 10xxxxxxb
122
+	ClassPrivate     Class = 192 // 11xxxxxxb
123
+	ClassBitmask     Class = 192 // 11xxxxxxb
124
+)
125
+
126
+var ClassMap = map[Class]string{
127
+	ClassUniversal:   "Universal",
128
+	ClassApplication: "Application",
129
+	ClassContext:     "Context",
130
+	ClassPrivate:     "Private",
131
+}
132
+
133
+type Type uint8
134
+
135
+const (
136
+	TypePrimitive   Type = 0  // xx0xxxxxb
137
+	TypeConstructed Type = 32 // xx1xxxxxb
138
+	TypeBitmask     Type = 32 // xx1xxxxxb
139
+)
140
+
141
+var TypeMap = map[Type]string{
142
+	TypePrimitive:   "Primitive",
143
+	TypeConstructed: "Constructed",
144
+}
145
+
146
+var Debug bool = false
147
+
148
+func PrintBytes(out io.Writer, buf []byte, indent string) {
149
+	data_lines := make([]string, (len(buf)/30)+1)
150
+	num_lines := make([]string, (len(buf)/30)+1)
151
+
152
+	for i, b := range buf {
153
+		data_lines[i/30] += fmt.Sprintf("%02x ", b)
154
+		num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
155
+	}
156
+
157
+	for i := 0; i < len(data_lines); i++ {
158
+		out.Write([]byte(indent + data_lines[i] + "\n"))
159
+		out.Write([]byte(indent + num_lines[i] + "\n\n"))
160
+	}
161
+}
162
+
163
+func PrintPacket(p *Packet) {
164
+	printPacket(os.Stdout, p, 0, false)
165
+}
166
+
167
+func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
168
+	indent_str := ""
169
+
170
+	for len(indent_str) != indent {
171
+		indent_str += " "
172
+	}
173
+
174
+	class_str := ClassMap[p.ClassType]
175
+
176
+	tagtype_str := TypeMap[p.TagType]
177
+
178
+	tag_str := fmt.Sprintf("0x%02X", p.Tag)
179
+
180
+	if p.ClassType == ClassUniversal {
181
+		tag_str = tagMap[p.Tag]
182
+	}
183
+
184
+	value := fmt.Sprint(p.Value)
185
+	description := ""
186
+
187
+	if p.Description != "" {
188
+		description = p.Description + ": "
189
+	}
190
+
191
+	fmt.Fprintf(out, "%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
192
+
193
+	if printBytes {
194
+		PrintBytes(out, p.Bytes(), indent_str)
195
+	}
196
+
197
+	for _, child := range p.Children {
198
+		printPacket(out, child, indent+1, printBytes)
199
+	}
200
+}
201
+
202
+// ReadPacket reads a single Packet from the reader
203
+func ReadPacket(reader io.Reader) (*Packet, error) {
204
+	p, _, err := readPacket(reader)
205
+	if err != nil {
206
+		return nil, err
207
+	}
208
+	return p, nil
209
+}
210
+
211
+func DecodeString(data []byte) string {
212
+	return string(data)
213
+}
214
+
215
+func ParseInt64(bytes []byte) (ret int64, err error) {
216
+	if len(bytes) > 8 {
217
+		// We'll overflow an int64 in this case.
218
+		err = fmt.Errorf("integer too large")
219
+		return
220
+	}
221
+	for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
222
+		ret <<= 8
223
+		ret |= int64(bytes[bytesRead])
224
+	}
225
+
226
+	// Shift up and down in order to sign extend the result.
227
+	ret <<= 64 - uint8(len(bytes))*8
228
+	ret >>= 64 - uint8(len(bytes))*8
229
+	return
230
+}
231
+
232
+func encodeInteger(i int64) []byte {
233
+	n := int64Length(i)
234
+	out := make([]byte, n)
235
+
236
+	var j int
237
+	for ; n > 0; n-- {
238
+		out[j] = (byte(i >> uint((n-1)*8)))
239
+		j++
240
+	}
241
+
242
+	return out
243
+}
244
+
245
+func int64Length(i int64) (numBytes int) {
246
+	numBytes = 1
247
+
248
+	for i > 127 {
249
+		numBytes++
250
+		i >>= 8
251
+	}
252
+
253
+	for i < -128 {
254
+		numBytes++
255
+		i >>= 8
256
+	}
257
+
258
+	return
259
+}
260
+
261
+// DecodePacket decodes the given bytes into a single Packet
262
+// If a decode error is encountered, nil is returned.
263
+func DecodePacket(data []byte) *Packet {
264
+	p, _, _ := readPacket(bytes.NewBuffer(data))
265
+
266
+	return p
267
+}
268
+
269
+// DecodePacketErr decodes the given bytes into a single Packet
270
+// If a decode error is encountered, nil is returned
271
+func DecodePacketErr(data []byte) (*Packet, error) {
272
+	p, _, err := readPacket(bytes.NewBuffer(data))
273
+	if err != nil {
274
+		return nil, err
275
+	}
276
+	return p, nil
277
+}
278
+
279
+// readPacket reads a single Packet from the reader, returning the number of bytes read
280
+func readPacket(reader io.Reader) (*Packet, int, error) {
281
+	identifier, length, read, err := readHeader(reader)
282
+	if err != nil {
283
+		return nil, read, err
284
+	}
285
+
286
+	p := &Packet{
287
+		Identifier: identifier,
288
+	}
289
+
290
+	p.Data = new(bytes.Buffer)
291
+	p.Children = make([]*Packet, 0, 2)
292
+	p.Value = nil
293
+
294
+	if p.TagType == TypeConstructed {
295
+		// TODO: if universal, ensure tag type is allowed to be constructed
296
+
297
+		// Track how much content we've read
298
+		contentRead := 0
299
+		for {
300
+			if length != LengthIndefinite {
301
+				// End if we've read what we've been told to
302
+				if contentRead == length {
303
+					break
304
+				}
305
+				// Detect if a packet boundary didn't fall on the expected length
306
+				if contentRead > length {
307
+					return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead)
308
+				}
309
+			}
310
+
311
+			// Read the next packet
312
+			child, r, err := readPacket(reader)
313
+			if err != nil {
314
+				return nil, read, err
315
+			}
316
+			contentRead += r
317
+			read += r
318
+
319
+			// Test is this is the EOC marker for our packet
320
+			if isEOCPacket(child) {
321
+				if length == LengthIndefinite {
322
+					break
323
+				}
324
+				return nil, read, errors.New("eoc child not allowed with definite length")
325
+			}
326
+
327
+			// Append and continue
328
+			p.AppendChild(child)
329
+		}
330
+		return p, read, nil
331
+	}
332
+
333
+	if length == LengthIndefinite {
334
+		return nil, read, errors.New("indefinite length used with primitive type")
335
+	}
336
+
337
+	// Read definite-length content
338
+	if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes {
339
+		return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes)
340
+	}
341
+	content := make([]byte, length, length)
342
+	if length > 0 {
343
+		_, err := io.ReadFull(reader, content)
344
+		if err != nil {
345
+			if err == io.EOF {
346
+				return nil, read, io.ErrUnexpectedEOF
347
+			}
348
+			return nil, read, err
349
+		}
350
+		read += length
351
+	}
352
+
353
+	if p.ClassType == ClassUniversal {
354
+		p.Data.Write(content)
355
+		p.ByteValue = content
356
+
357
+		switch p.Tag {
358
+		case TagEOC:
359
+		case TagBoolean:
360
+			val, _ := ParseInt64(content)
361
+
362
+			p.Value = val != 0
363
+		case TagInteger:
364
+			p.Value, _ = ParseInt64(content)
365
+		case TagBitString:
366
+		case TagOctetString:
367
+			// the actual string encoding is not known here
368
+			// (e.g. for LDAP content is already an UTF8-encoded
369
+			// string). Return the data without further processing
370
+			p.Value = DecodeString(content)
371
+		case TagNULL:
372
+		case TagObjectIdentifier:
373
+		case TagObjectDescriptor:
374
+		case TagExternal:
375
+		case TagRealFloat:
376
+		case TagEnumerated:
377
+			p.Value, _ = ParseInt64(content)
378
+		case TagEmbeddedPDV:
379
+		case TagUTF8String:
380
+			p.Value = DecodeString(content)
381
+		case TagRelativeOID:
382
+		case TagSequence:
383
+		case TagSet:
384
+		case TagNumericString:
385
+		case TagPrintableString:
386
+			p.Value = DecodeString(content)
387
+		case TagT61String:
388
+		case TagVideotexString:
389
+		case TagIA5String:
390
+		case TagUTCTime:
391
+		case TagGeneralizedTime:
392
+		case TagGraphicString:
393
+		case TagVisibleString:
394
+		case TagGeneralString:
395
+		case TagUniversalString:
396
+		case TagCharacterString:
397
+		case TagBMPString:
398
+		}
399
+	} else {
400
+		p.Data.Write(content)
401
+	}
402
+
403
+	return p, read, nil
404
+}
405
+
406
+func (p *Packet) Bytes() []byte {
407
+	var out bytes.Buffer
408
+
409
+	out.Write(encodeIdentifier(p.Identifier))
410
+	out.Write(encodeLength(p.Data.Len()))
411
+	out.Write(p.Data.Bytes())
412
+
413
+	return out.Bytes()
414
+}
415
+
416
+func (p *Packet) AppendChild(child *Packet) {
417
+	p.Data.Write(child.Bytes())
418
+	p.Children = append(p.Children, child)
419
+}
420
+
421
+func Encode(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet {
422
+	p := new(Packet)
423
+
424
+	p.ClassType = ClassType
425
+	p.TagType = TagType
426
+	p.Tag = Tag
427
+	p.Data = new(bytes.Buffer)
428
+
429
+	p.Children = make([]*Packet, 0, 2)
430
+
431
+	p.Value = Value
432
+	p.Description = Description
433
+
434
+	if Value != nil {
435
+		v := reflect.ValueOf(Value)
436
+
437
+		if ClassType == ClassUniversal {
438
+			switch Tag {
439
+			case TagOctetString:
440
+				sv, ok := v.Interface().(string)
441
+
442
+				if ok {
443
+					p.Data.Write([]byte(sv))
444
+				}
445
+			}
446
+		}
447
+	}
448
+
449
+	return p
450
+}
451
+
452
+func NewSequence(Description string) *Packet {
453
+	return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, Description)
454
+}
455
+
456
+func NewBoolean(ClassType Class, TagType Type, Tag Tag, Value bool, Description string) *Packet {
457
+	intValue := int64(0)
458
+
459
+	if Value {
460
+		intValue = 1
461
+	}
462
+
463
+	p := Encode(ClassType, TagType, Tag, nil, Description)
464
+
465
+	p.Value = Value
466
+	p.Data.Write(encodeInteger(intValue))
467
+
468
+	return p
469
+}
470
+
471
+func NewInteger(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet {
472
+	p := Encode(ClassType, TagType, Tag, nil, Description)
473
+
474
+	p.Value = Value
475
+	switch v := Value.(type) {
476
+	case int:
477
+		p.Data.Write(encodeInteger(int64(v)))
478
+	case uint:
479
+		p.Data.Write(encodeInteger(int64(v)))
480
+	case int64:
481
+		p.Data.Write(encodeInteger(v))
482
+	case uint64:
483
+		// TODO : check range or add encodeUInt...
484
+		p.Data.Write(encodeInteger(int64(v)))
485
+	case int32:
486
+		p.Data.Write(encodeInteger(int64(v)))
487
+	case uint32:
488
+		p.Data.Write(encodeInteger(int64(v)))
489
+	case int16:
490
+		p.Data.Write(encodeInteger(int64(v)))
491
+	case uint16:
492
+		p.Data.Write(encodeInteger(int64(v)))
493
+	case int8:
494
+		p.Data.Write(encodeInteger(int64(v)))
495
+	case uint8:
496
+		p.Data.Write(encodeInteger(int64(v)))
497
+	default:
498
+		// TODO : add support for big.Int ?
499
+		panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v))
500
+	}
501
+
502
+	return p
503
+}
504
+
505
+func NewString(ClassType Class, TagType Type, Tag Tag, Value, Description string) *Packet {
506
+	p := Encode(ClassType, TagType, Tag, nil, Description)
507
+
508
+	p.Value = Value
509
+	p.Data.Write([]byte(Value))
510
+
511
+	return p
512
+}

+ 25
- 0
vendor/github.com/go-asn1-ber/asn1-ber/content_int.go View File

@@ -0,0 +1,25 @@
1
+package ber
2
+
3
+func encodeUnsignedInteger(i uint64) []byte {
4
+	n := uint64Length(i)
5
+	out := make([]byte, n)
6
+
7
+	var j int
8
+	for ; n > 0; n-- {
9
+		out[j] = (byte(i >> uint((n-1)*8)))
10
+		j++
11
+	}
12
+
13
+	return out
14
+}
15
+
16
+func uint64Length(i uint64) (numBytes int) {
17
+	numBytes = 1
18
+
19
+	for i > 255 {
20
+		numBytes++
21
+		i >>= 8
22
+	}
23
+
24
+	return
25
+}

+ 3
- 0
vendor/github.com/go-asn1-ber/asn1-ber/go.mod View File

@@ -0,0 +1,3 @@
1
+module github.com/go-asn1-ber/asn1-ber
2
+
3
+go 1.13

+ 35
- 0
vendor/github.com/go-asn1-ber/asn1-ber/header.go View File

@@ -0,0 +1,35 @@
1
+package ber
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+	"io"
7
+)
8
+
9
+func readHeader(reader io.Reader) (identifier Identifier, length int, read int, err error) {
10
+	if i, c, err := readIdentifier(reader); err != nil {
11
+		return Identifier{}, 0, read, err
12
+	} else {
13
+		identifier = i
14
+		read += c
15
+	}
16
+
17
+	if l, c, err := readLength(reader); err != nil {
18
+		return Identifier{}, 0, read, err
19
+	} else {
20
+		length = l
21
+		read += c
22
+	}
23
+
24
+	// Validate length type with identifier (x.600, 8.1.3.2.a)
25
+	if length == LengthIndefinite && identifier.TagType == TypePrimitive {
26
+		return Identifier{}, 0, read, errors.New("indefinite length used with primitive type")
27
+	}
28
+
29
+	if length < LengthIndefinite {
30
+		err = fmt.Errorf("length cannot be less than %d", LengthIndefinite)
31
+		return
32
+	}
33
+
34
+	return identifier, length, read, nil
35
+}

+ 112
- 0
vendor/github.com/go-asn1-ber/asn1-ber/identifier.go View File

@@ -0,0 +1,112 @@
1
+package ber
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+	"io"
7
+)
8
+
9
+func readIdentifier(reader io.Reader) (Identifier, int, error) {
10
+	identifier := Identifier{}
11
+	read := 0
12
+
13
+	// identifier byte
14
+	b, err := readByte(reader)
15
+	if err != nil {
16
+		if Debug {
17
+			fmt.Printf("error reading identifier byte: %v\n", err)
18
+		}
19
+		return Identifier{}, read, err
20
+	}
21
+	read++
22
+
23
+	identifier.ClassType = Class(b) & ClassBitmask
24
+	identifier.TagType = Type(b) & TypeBitmask
25
+
26
+	if tag := Tag(b) & TagBitmask; tag != HighTag {
27
+		// short-form tag
28
+		identifier.Tag = tag
29
+		return identifier, read, nil
30
+	}
31
+
32
+	// high-tag-number tag
33
+	tagBytes := 0
34
+	for {
35
+		b, err := readByte(reader)
36
+		if err != nil {
37
+			if Debug {
38
+				fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err)
39
+			}
40
+			return Identifier{}, read, err
41
+		}
42
+		tagBytes++
43
+		read++
44
+
45
+		// Lowest 7 bits get appended to the tag value (x.690, 8.1.2.4.2.b)
46
+		identifier.Tag <<= 7
47
+		identifier.Tag |= Tag(b) & HighTagValueBitmask
48
+
49
+		// First byte may not be all zeros (x.690, 8.1.2.4.2.c)
50
+		if tagBytes == 1 && identifier.Tag == 0 {
51
+			return Identifier{}, read, errors.New("invalid first high-tag-number tag byte")
52
+		}
53
+		// Overflow of int64
54
+		// TODO: support big int tags?
55
+		if tagBytes > 9 {
56
+			return Identifier{}, read, errors.New("high-tag-number tag overflow")
57
+		}
58
+
59
+		// Top bit of 0 means this is the last byte in the high-tag-number tag (x.690, 8.1.2.4.2.a)
60
+		if Tag(b)&HighTagContinueBitmask == 0 {
61
+			break
62
+		}
63
+	}
64
+
65
+	return identifier, read, nil
66
+}
67
+
68
+func encodeIdentifier(identifier Identifier) []byte {
69
+	b := []byte{0x0}
70
+	b[0] |= byte(identifier.ClassType)
71
+	b[0] |= byte(identifier.TagType)
72
+
73
+	if identifier.Tag < HighTag {
74
+		// Short-form
75
+		b[0] |= byte(identifier.Tag)
76
+	} else {
77
+		// high-tag-number
78
+		b[0] |= byte(HighTag)
79
+
80
+		tag := identifier.Tag
81
+
82
+		b = append(b, encodeHighTag(tag)...)
83
+	}
84
+	return b
85
+}
86
+
87
+func encodeHighTag(tag Tag) []byte {
88
+	// set cap=4 to hopefully avoid additional allocations
89
+	b := make([]byte, 0, 4)
90
+	for tag != 0 {
91
+		// t := last 7 bits of tag (HighTagValueBitmask = 0x7F)
92
+		t := tag & HighTagValueBitmask
93
+
94
+		// right shift tag 7 to remove what was just pulled off
95
+		tag >>= 7
96
+
97
+		// if b already has entries this entry needs a continuation bit (0x80)
98
+		if len(b) != 0 {
99
+			t |= HighTagContinueBitmask
100
+		}
101
+
102
+		b = append(b, byte(t))
103
+	}
104
+	// reverse
105
+	// since bits were pulled off 'tag' small to high the byte slice is in reverse order.
106
+	// example: tag = 0xFF results in {0x7F, 0x01 + 0x80 (continuation bit)}
107
+	// this needs to be reversed into 0x81 0x7F
108
+	for i, j := 0, len(b)-1; i < len(b)/2; i++ {
109
+		b[i], b[j-i] = b[j-i], b[i]
110
+	}
111
+	return b
112
+}

+ 81
- 0
vendor/github.com/go-asn1-ber/asn1-ber/length.go View File

@@ -0,0 +1,81 @@
1
+package ber
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+	"io"
7
+)
8
+
9
+func readLength(reader io.Reader) (length int, read int, err error) {
10
+	// length byte
11
+	b, err := readByte(reader)
12
+	if err != nil {
13
+		if Debug {
14
+			fmt.Printf("error reading length byte: %v\n", err)
15
+		}
16
+		return 0, 0, err
17
+	}
18
+	read++
19
+
20
+	switch {
21
+	case b == 0xFF:
22
+		// Invalid 0xFF (x.600, 8.1.3.5.c)
23
+		return 0, read, errors.New("invalid length byte 0xff")
24
+
25
+	case b == LengthLongFormBitmask:
26
+		// Indefinite form, we have to decode packets until we encounter an EOC packet (x.600, 8.1.3.6)
27
+		length = LengthIndefinite
28
+
29
+	case b&LengthLongFormBitmask == 0:
30
+		// Short definite form, extract the length from the bottom 7 bits (x.600, 8.1.3.4)
31
+		length = int(b) & LengthValueBitmask
32
+
33
+	case b&LengthLongFormBitmask != 0:
34
+		// Long definite form, extract the number of length bytes to follow from the bottom 7 bits (x.600, 8.1.3.5.b)
35
+		lengthBytes := int(b) & LengthValueBitmask
36
+		// Protect against overflow
37
+		// TODO: support big int length?
38
+		if lengthBytes > 8 {
39
+			return 0, read, errors.New("long-form length overflow")
40
+		}
41
+
42
+		// Accumulate into a 64-bit variable
43
+		var length64 int64
44
+		for i := 0; i < lengthBytes; i++ {
45
+			b, err = readByte(reader)
46
+			if err != nil {
47
+				if Debug {
48
+					fmt.Printf("error reading long-form length byte %d: %v\n", i, err)
49
+				}
50
+				return 0, read, err
51
+			}
52
+			read++
53
+
54
+			// x.600, 8.1.3.5
55
+			length64 <<= 8
56
+			length64 |= int64(b)
57
+		}
58
+
59
+		// Cast to a platform-specific integer
60
+		length = int(length64)
61
+		// Ensure we didn't overflow
62
+		if int64(length) != length64 {
63
+			return 0, read, errors.New("long-form length overflow")
64
+		}
65
+
66
+	default:
67
+		return 0, read, errors.New("invalid length byte")
68
+	}
69
+
70
+	return length, read, nil
71
+}
72
+
73
+func encodeLength(length int) []byte {
74
+	length_bytes := encodeUnsignedInteger(uint64(length))
75
+	if length > 127 || len(length_bytes) > 1 {
76
+		longFormBytes := []byte{(LengthLongFormBitmask | byte(len(length_bytes)))}
77
+		longFormBytes = append(longFormBytes, length_bytes...)
78
+		length_bytes = longFormBytes
79
+	}
80
+	return length_bytes
81
+}

+ 24
- 0
vendor/github.com/go-asn1-ber/asn1-ber/util.go View File

@@ -0,0 +1,24 @@
1
+package ber
2
+
3
+import "io"
4
+
5
+func readByte(reader io.Reader) (byte, error) {
6
+	bytes := make([]byte, 1, 1)
7
+	_, err := io.ReadFull(reader, bytes)
8
+	if err != nil {
9
+		if err == io.EOF {
10
+			return 0, io.ErrUnexpectedEOF
11
+		}
12
+		return 0, err
13
+	}
14
+	return bytes[0], nil
15
+}
16
+
17
+func isEOCPacket(p *Packet) bool {
18
+	return p != nil &&
19
+		p.Tag == TagEOC &&
20
+		p.ClassType == ClassUniversal &&
21
+		p.TagType == TypePrimitive &&
22
+		len(p.ByteValue) == 0 &&
23
+		len(p.Children) == 0
24
+}

+ 22
- 0
vendor/github.com/go-ldap/ldap/v3/LICENSE View File

@@ -0,0 +1,22 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)
4
+Portions copyright (c) 2015-2016 go-ldap Authors
5
+
6
+Permission is hereby granted, free of charge, to any person obtaining a copy
7
+of this software and associated documentation files (the "Software"), to deal
8
+in the Software without restriction, including without limitation the rights
9
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+copies of the Software, and to permit persons to whom the Software is
11
+furnished to do so, subject to the following conditions:
12
+
13
+The above copyright notice and this permission notice shall be included in all
14
+copies or substantial portions of the Software.
15
+
16
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+SOFTWARE.

+ 91
- 0
vendor/github.com/go-ldap/ldap/v3/add.go View File

@@ -0,0 +1,91 @@
1
+package ldap
2
+
3
+import (
4
+	"log"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// Attribute represents an LDAP attribute
10
+type Attribute struct {
11
+	// Type is the name of the LDAP attribute
12
+	Type string
13
+	// Vals are the LDAP attribute values
14
+	Vals []string
15
+}
16
+
17
+func (a *Attribute) encode() *ber.Packet {
18
+	seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attribute")
19
+	seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.Type, "Type"))
20
+	set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
21
+	for _, value := range a.Vals {
22
+		set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
23
+	}
24
+	seq.AppendChild(set)
25
+	return seq
26
+}
27
+
28
+// AddRequest represents an LDAP AddRequest operation
29
+type AddRequest struct {
30
+	// DN identifies the entry being added
31
+	DN string
32
+	// Attributes list the attributes of the new entry
33
+	Attributes []Attribute
34
+	// Controls hold optional controls to send with the request
35
+	Controls []Control
36
+}
37
+
38
+func (req *AddRequest) appendTo(envelope *ber.Packet) error {
39
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request")
40
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
41
+	attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
42
+	for _, attribute := range req.Attributes {
43
+		attributes.AppendChild(attribute.encode())
44
+	}
45
+	pkt.AppendChild(attributes)
46
+
47
+	envelope.AppendChild(pkt)
48
+	if len(req.Controls) > 0 {
49
+		envelope.AppendChild(encodeControls(req.Controls))
50
+	}
51
+
52
+	return nil
53
+}
54
+
55
+// Attribute adds an attribute with the given type and values
56
+func (req *AddRequest) Attribute(attrType string, attrVals []string) {
57
+	req.Attributes = append(req.Attributes, Attribute{Type: attrType, Vals: attrVals})
58
+}
59
+
60
+// NewAddRequest returns an AddRequest for the given DN, with no attributes
61
+func NewAddRequest(dn string, controls []Control) *AddRequest {
62
+	return &AddRequest{
63
+		DN:       dn,
64
+		Controls: controls,
65
+	}
66
+
67
+}
68
+
69
+// Add performs the given AddRequest
70
+func (l *Conn) Add(addRequest *AddRequest) error {
71
+	msgCtx, err := l.doRequest(addRequest)
72
+	if err != nil {
73
+		return err
74
+	}
75
+	defer l.finishMessage(msgCtx)
76
+
77
+	packet, err := l.readPacket(msgCtx)
78
+	if err != nil {
79
+		return err
80
+	}
81
+
82
+	if packet.Children[1].Tag == ApplicationAddResponse {
83
+		err := GetLDAPError(packet)
84
+		if err != nil {
85
+			return err
86
+		}
87
+	} else {
88
+		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
89
+	}
90
+	return nil
91
+}

+ 152
- 0
vendor/github.com/go-ldap/ldap/v3/bind.go View File

@@ -0,0 +1,152 @@
1
+package ldap
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+
7
+	ber "github.com/go-asn1-ber/asn1-ber"
8
+)
9
+
10
+// SimpleBindRequest represents a username/password bind operation
11
+type SimpleBindRequest struct {
12
+	// Username is the name of the Directory object that the client wishes to bind as
13
+	Username string
14
+	// Password is the credentials to bind with
15
+	Password string
16
+	// Controls are optional controls to send with the bind request
17
+	Controls []Control
18
+	// AllowEmptyPassword sets whether the client allows binding with an empty password
19
+	// (normally used for unauthenticated bind).
20
+	AllowEmptyPassword bool
21
+}
22
+
23
+// SimpleBindResult contains the response from the server
24
+type SimpleBindResult struct {
25
+	Controls []Control
26
+}
27
+
28
+// NewSimpleBindRequest returns a bind request
29
+func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
30
+	return &SimpleBindRequest{
31
+		Username:           username,
32
+		Password:           password,
33
+		Controls:           controls,
34
+		AllowEmptyPassword: false,
35
+	}
36
+}
37
+
38
+func (req *SimpleBindRequest) appendTo(envelope *ber.Packet) error {
39
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
40
+	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
41
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Username, "User Name"))
42
+	pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.Password, "Password"))
43
+
44
+	envelope.AppendChild(pkt)
45
+	if len(req.Controls) > 0 {
46
+		envelope.AppendChild(encodeControls(req.Controls))
47
+	}
48
+
49
+	return nil
50
+}
51
+
52
+// SimpleBind performs the simple bind operation defined in the given request
53
+func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
54
+	if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
55
+		return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
56
+	}
57
+
58
+	msgCtx, err := l.doRequest(simpleBindRequest)
59
+	if err != nil {
60
+		return nil, err
61
+	}
62
+	defer l.finishMessage(msgCtx)
63
+
64
+	packet, err := l.readPacket(msgCtx)
65
+	if err != nil {
66
+		return nil, err
67
+	}
68
+
69
+	result := &SimpleBindResult{
70
+		Controls: make([]Control, 0),
71
+	}
72
+
73
+	if len(packet.Children) == 3 {
74
+		for _, child := range packet.Children[2].Children {
75
+			decodedChild, decodeErr := DecodeControl(child)
76
+			if decodeErr != nil {
77
+				return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
78
+			}
79
+			result.Controls = append(result.Controls, decodedChild)
80
+		}
81
+	}
82
+
83
+	err = GetLDAPError(packet)
84
+	return result, err
85
+}
86
+
87
+// Bind performs a bind with the given username and password.
88
+//
89
+// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
90
+// for that.
91
+func (l *Conn) Bind(username, password string) error {
92
+	req := &SimpleBindRequest{
93
+		Username:           username,
94
+		Password:           password,
95
+		AllowEmptyPassword: false,
96
+	}
97
+	_, err := l.SimpleBind(req)
98
+	return err
99
+}
100
+
101
+// UnauthenticatedBind performs an unauthenticated bind.
102
+//
103
+// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
104
+// authenticated or otherwise validated by the LDAP server.
105
+//
106
+// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
107
+// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
108
+func (l *Conn) UnauthenticatedBind(username string) error {
109
+	req := &SimpleBindRequest{
110
+		Username:           username,
111
+		Password:           "",
112
+		AllowEmptyPassword: true,
113
+	}
114
+	_, err := l.SimpleBind(req)
115
+	return err
116
+}
117
+
118
+var externalBindRequest = requestFunc(func(envelope *ber.Packet) error {
119
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
120
+	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
121
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "User Name"))
122
+
123
+	saslAuth := ber.Encode(ber.ClassContext, ber.TypeConstructed, 3, "", "authentication")
124
+	saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "EXTERNAL", "SASL Mech"))
125
+	saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "SASL Cred"))
126
+
127
+	pkt.AppendChild(saslAuth)
128
+
129
+	envelope.AppendChild(pkt)
130
+
131
+	return nil
132
+})
133
+
134
+// ExternalBind performs SASL/EXTERNAL authentication.
135
+//
136
+// Use ldap.DialURL("ldapi://") to connect to the Unix socket before ExternalBind.
137
+//
138
+// See https://tools.ietf.org/html/rfc4422#appendix-A
139
+func (l *Conn) ExternalBind() error {
140
+	msgCtx, err := l.doRequest(externalBindRequest)
141
+	if err != nil {
142
+		return err
143
+	}
144
+	defer l.finishMessage(msgCtx)
145
+
146
+	packet, err := l.readPacket(msgCtx)
147
+	if err != nil {
148
+		return err
149
+	}
150
+
151
+	return GetLDAPError(packet)
152
+}

+ 30
- 0
vendor/github.com/go-ldap/ldap/v3/client.go View File

@@ -0,0 +1,30 @@
1
+package ldap
2
+
3
+import (
4
+	"crypto/tls"
5
+	"time"
6
+)
7
+
8
+// Client knows how to interact with an LDAP server
9
+type Client interface {
10
+	Start()
11
+	StartTLS(*tls.Config) error
12
+	Close()
13
+	SetTimeout(time.Duration)
14
+
15
+	Bind(username, password string) error
16
+	UnauthenticatedBind(username string) error
17
+	SimpleBind(*SimpleBindRequest) (*SimpleBindResult, error)
18
+	ExternalBind() error
19
+
20
+	Add(*AddRequest) error
21
+	Del(*DelRequest) error
22
+	Modify(*ModifyRequest) error
23
+	ModifyDN(*ModifyDNRequest) error
24
+
25
+	Compare(dn, attribute, value string) (bool, error)
26
+	PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error)
27
+
28
+	Search(*SearchRequest) (*SearchResult, error)
29
+	SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)
30
+}

+ 61
- 0
vendor/github.com/go-ldap/ldap/v3/compare.go View File

@@ -0,0 +1,61 @@
1
+package ldap
2
+
3
+import (
4
+	"fmt"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// CompareRequest represents an LDAP CompareRequest operation.
10
+type CompareRequest struct {
11
+	DN        string
12
+	Attribute string
13
+	Value     string
14
+}
15
+
16
+func (req *CompareRequest) appendTo(envelope *ber.Packet) error {
17
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, "Compare Request")
18
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
19
+
20
+	ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion")
21
+	ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Attribute, "AttributeDesc"))
22
+	ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Value, "AssertionValue"))
23
+
24
+	pkt.AppendChild(ava)
25
+
26
+	envelope.AppendChild(pkt)
27
+
28
+	return nil
29
+}
30
+
31
+// Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise
32
+// false with any error that occurs if any.
33
+func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
34
+	msgCtx, err := l.doRequest(&CompareRequest{
35
+		DN:        dn,
36
+		Attribute: attribute,
37
+		Value:     value})
38
+	if err != nil {
39
+		return false, err
40
+	}
41
+	defer l.finishMessage(msgCtx)
42
+
43
+	packet, err := l.readPacket(msgCtx)
44
+	if err != nil {
45
+		return false, err
46
+	}
47
+
48
+	if packet.Children[1].Tag == ApplicationCompareResponse {
49
+		err := GetLDAPError(packet)
50
+
51
+		switch {
52
+		case IsErrorWithCode(err, LDAPResultCompareTrue):
53
+			return true, nil
54
+		case IsErrorWithCode(err, LDAPResultCompareFalse):
55
+			return false, nil
56
+		default:
57
+			return false, err
58
+		}
59
+	}
60
+	return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag)
61
+}

+ 565
- 0
vendor/github.com/go-ldap/ldap/v3/conn.go View File

@@ -0,0 +1,565 @@
1
+package ldap
2
+
3
+import (
4
+	"crypto/tls"
5
+	"errors"
6
+	"fmt"
7
+	"log"
8
+	"net"
9
+	"net/url"
10
+	"sync"
11
+	"sync/atomic"
12
+	"time"
13
+
14
+	ber "github.com/go-asn1-ber/asn1-ber"
15
+)
16
+
17
+const (
18
+	// MessageQuit causes the processMessages loop to exit
19
+	MessageQuit = 0
20
+	// MessageRequest sends a request to the server
21
+	MessageRequest = 1
22
+	// MessageResponse receives a response from the server
23
+	MessageResponse = 2
24
+	// MessageFinish indicates the client considers a particular message ID to be finished
25
+	MessageFinish = 3
26
+	// MessageTimeout indicates the client-specified timeout for a particular message ID has been reached
27
+	MessageTimeout = 4
28
+)
29
+
30
+const (
31
+	// DefaultLdapPort default ldap port for pure TCP connection
32
+	DefaultLdapPort = "389"
33
+	// DefaultLdapsPort default ldap port for SSL connection
34
+	DefaultLdapsPort = "636"
35
+)
36
+
37
+// PacketResponse contains the packet or error encountered reading a response
38
+type PacketResponse struct {
39
+	// Packet is the packet read from the server
40
+	Packet *ber.Packet
41
+	// Error is an error encountered while reading
42
+	Error error
43
+}
44
+
45
+// ReadPacket returns the packet or an error
46
+func (pr *PacketResponse) ReadPacket() (*ber.Packet, error) {
47
+	if (pr == nil) || (pr.Packet == nil && pr.Error == nil) {
48
+		return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve response"))
49
+	}
50
+	return pr.Packet, pr.Error
51
+}
52
+
53
+type messageContext struct {
54
+	id int64
55
+	// close(done) should only be called from finishMessage()
56
+	done chan struct{}
57
+	// close(responses) should only be called from processMessages(), and only sent to from sendResponse()
58
+	responses chan *PacketResponse
59
+}
60
+
61
+// sendResponse should only be called within the processMessages() loop which
62
+// is also responsible for closing the responses channel.
63
+func (msgCtx *messageContext) sendResponse(packet *PacketResponse) {
64
+	select {
65
+	case msgCtx.responses <- packet:
66
+		// Successfully sent packet to message handler.
67
+	case <-msgCtx.done:
68
+		// The request handler is done and will not receive more
69
+		// packets.
70
+	}
71
+}
72
+
73
+type messagePacket struct {
74
+	Op        int
75
+	MessageID int64
76
+	Packet    *ber.Packet
77
+	Context   *messageContext
78
+}
79
+
80
+type sendMessageFlags uint
81
+
82
+const (
83
+	startTLS sendMessageFlags = 1 << iota
84
+)
85
+
86
+// Conn represents an LDAP Connection
87
+type Conn struct {
88
+	// requestTimeout is loaded atomically
89
+	// so we need to ensure 64-bit alignment on 32-bit platforms.
90
+	requestTimeout      int64
91
+	conn                net.Conn
92
+	isTLS               bool
93
+	closing             uint32
94
+	closeErr            atomic.Value
95
+	isStartingTLS       bool
96
+	Debug               debugging
97
+	chanConfirm         chan struct{}
98
+	messageContexts     map[int64]*messageContext
99
+	chanMessage         chan *messagePacket
100
+	chanMessageID       chan int64
101
+	wgClose             sync.WaitGroup
102
+	outstandingRequests uint
103
+	messageMutex        sync.Mutex
104
+}
105
+
106
+var _ Client = &Conn{}
107
+
108
+// DefaultTimeout is a package-level variable that sets the timeout value
109
+// used for the Dial and DialTLS methods.
110
+//
111
+// WARNING: since this is a package-level variable, setting this value from
112
+// multiple places will probably result in undesired behaviour.
113
+var DefaultTimeout = 60 * time.Second
114
+
115
+// DialOpt configures DialContext.
116
+type DialOpt func(*DialContext)
117
+
118
+// DialWithDialer updates net.Dialer in DialContext.
119
+func DialWithDialer(d *net.Dialer) DialOpt {
120
+	return func(dc *DialContext) {
121
+		dc.d = d
122
+	}
123
+}
124
+
125
+// DialWithTLSConfig updates tls.Config in DialContext.
126
+func DialWithTLSConfig(tc *tls.Config) DialOpt {
127
+	return func(dc *DialContext) {
128
+		dc.tc = tc
129
+	}
130
+}
131
+
132
+// DialContext contains necessary parameters to dial the given ldap URL.
133
+type DialContext struct {
134
+	d  *net.Dialer
135
+	tc *tls.Config
136
+}
137
+
138
+func (dc *DialContext) dial(u *url.URL) (net.Conn, error) {
139
+	if u.Scheme == "ldapi" {
140
+		if u.Path == "" || u.Path == "/" {
141
+			u.Path = "/var/run/slapd/ldapi"
142
+		}
143
+		return dc.d.Dial("unix", u.Path)
144
+	}
145
+
146
+	host, port, err := net.SplitHostPort(u.Host)
147
+	if err != nil {
148
+		// we asume that error is due to missing port
149
+		host = u.Host
150
+		port = ""
151
+	}
152
+
153
+	switch u.Scheme {
154
+	case "ldap":
155
+		if port == "" {
156
+			port = DefaultLdapPort
157
+		}
158
+		return dc.d.Dial("tcp", net.JoinHostPort(host, port))
159
+	case "ldaps":
160
+		if port == "" {
161
+			port = DefaultLdapsPort
162
+		}
163
+		return tls.DialWithDialer(dc.d, "tcp", net.JoinHostPort(host, port), dc.tc)
164
+	}
165
+
166
+	return nil, fmt.Errorf("Unknown scheme '%s'", u.Scheme)
167
+}
168
+
169
+// Dial connects to the given address on the given network using net.Dial
170
+// and then returns a new Conn for the connection.
171
+// @deprecated Use DialURL instead.
172
+func Dial(network, addr string) (*Conn, error) {
173
+	c, err := net.DialTimeout(network, addr, DefaultTimeout)
174
+	if err != nil {
175
+		return nil, NewError(ErrorNetwork, err)
176
+	}
177
+	conn := NewConn(c, false)
178
+	conn.Start()
179
+	return conn, nil
180
+}
181
+
182
+// DialTLS connects to the given address on the given network using tls.Dial
183
+// and then returns a new Conn for the connection.
184
+// @deprecated Use DialURL instead.
185
+func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
186
+	c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
187
+	if err != nil {
188
+		return nil, NewError(ErrorNetwork, err)
189
+	}
190
+	conn := NewConn(c, true)
191
+	conn.Start()
192
+	return conn, nil
193
+}
194
+
195
+// DialURL connects to the given ldap URL.
196
+// The following schemas are supported: ldap://, ldaps://, ldapi://.
197
+// On success a new Conn for the connection is returned.
198
+func DialURL(addr string, opts ...DialOpt) (*Conn, error) {
199
+	u, err := url.Parse(addr)
200
+	if err != nil {
201
+		return nil, NewError(ErrorNetwork, err)
202
+	}
203
+
204
+	var dc DialContext
205
+	for _, opt := range opts {
206
+		opt(&dc)
207
+	}
208
+	if dc.d == nil {
209
+		dc.d = &net.Dialer{Timeout: DefaultTimeout}
210
+	}
211
+
212
+	c, err := dc.dial(u)
213
+	if err != nil {
214
+		return nil, NewError(ErrorNetwork, err)
215
+	}
216
+
217
+	conn := NewConn(c, u.Scheme == "ldaps")
218
+	conn.Start()
219
+	return conn, nil
220
+}
221
+
222
+// NewConn returns a new Conn using conn for network I/O.
223
+func NewConn(conn net.Conn, isTLS bool) *Conn {
224
+	return &Conn{
225
+		conn:            conn,
226
+		chanConfirm:     make(chan struct{}),
227
+		chanMessageID:   make(chan int64),
228
+		chanMessage:     make(chan *messagePacket, 10),
229
+		messageContexts: map[int64]*messageContext{},
230
+		requestTimeout:  0,
231
+		isTLS:           isTLS,
232
+	}
233
+}
234
+
235
+// Start initializes goroutines to read responses and process messages
236
+func (l *Conn) Start() {
237
+	l.wgClose.Add(1)
238
+	go l.reader()
239
+	go l.processMessages()
240
+}
241
+
242
+// IsClosing returns whether or not we're currently closing.
243
+func (l *Conn) IsClosing() bool {
244
+	return atomic.LoadUint32(&l.closing) == 1
245
+}
246
+
247
+// setClosing sets the closing value to true
248
+func (l *Conn) setClosing() bool {
249
+	return atomic.CompareAndSwapUint32(&l.closing, 0, 1)
250
+}
251
+
252
+// Close closes the connection.
253
+func (l *Conn) Close() {
254
+	l.messageMutex.Lock()
255
+	defer l.messageMutex.Unlock()
256
+
257
+	if l.setClosing() {
258
+		l.Debug.Printf("Sending quit message and waiting for confirmation")
259
+		l.chanMessage <- &messagePacket{Op: MessageQuit}
260
+		<-l.chanConfirm
261
+		close(l.chanMessage)
262
+
263
+		l.Debug.Printf("Closing network connection")
264
+		if err := l.conn.Close(); err != nil {
265
+			log.Println(err)
266
+		}
267
+
268
+		l.wgClose.Done()
269
+	}
270
+	l.wgClose.Wait()
271
+}
272
+
273
+// SetTimeout sets the time after a request is sent that a MessageTimeout triggers
274
+func (l *Conn) SetTimeout(timeout time.Duration) {
275
+	if timeout > 0 {
276
+		atomic.StoreInt64(&l.requestTimeout, int64(timeout))
277
+	}
278
+}
279
+
280
+// Returns the next available messageID
281
+func (l *Conn) nextMessageID() int64 {
282
+	if messageID, ok := <-l.chanMessageID; ok {
283
+		return messageID
284
+	}
285
+	return 0
286
+}
287
+
288
+// StartTLS sends the command to start a TLS session and then creates a new TLS Client
289
+func (l *Conn) StartTLS(config *tls.Config) error {
290
+	if l.isTLS {
291
+		return NewError(ErrorNetwork, errors.New("ldap: already encrypted"))
292
+	}
293
+
294
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
295
+	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
296
+	request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
297
+	request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
298
+	packet.AppendChild(request)
299
+	l.Debug.PrintPacket(packet)
300
+
301
+	msgCtx, err := l.sendMessageWithFlags(packet, startTLS)
302
+	if err != nil {
303
+		return err
304
+	}
305
+	defer l.finishMessage(msgCtx)
306
+
307
+	l.Debug.Printf("%d: waiting for response", msgCtx.id)
308
+
309
+	packetResponse, ok := <-msgCtx.responses
310
+	if !ok {
311
+		return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
312
+	}
313
+	packet, err = packetResponse.ReadPacket()
314
+	l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
315
+	if err != nil {
316
+		return err
317
+	}
318
+
319
+	if l.Debug {
320
+		if err := addLDAPDescriptions(packet); err != nil {
321
+			l.Close()
322
+			return err
323
+		}
324
+		l.Debug.PrintPacket(packet)
325
+	}
326
+
327
+	if err := GetLDAPError(packet); err == nil {
328
+		conn := tls.Client(l.conn, config)
329
+
330
+		if connErr := conn.Handshake(); connErr != nil {
331
+			l.Close()
332
+			return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", connErr))
333
+		}
334
+
335
+		l.isTLS = true
336
+		l.conn = conn
337
+	} else {
338
+		return err
339
+	}
340
+	go l.reader()
341
+
342
+	return nil
343
+}
344
+
345
+// TLSConnectionState returns the client's TLS connection state.
346
+// The return values are their zero values if StartTLS did
347
+// not succeed.
348
+func (l *Conn) TLSConnectionState() (state tls.ConnectionState, ok bool) {
349
+	tc, ok := l.conn.(*tls.Conn)
350
+	if !ok {
351
+		return
352
+	}
353
+	return tc.ConnectionState(), true
354
+}
355
+
356
+func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) {
357
+	return l.sendMessageWithFlags(packet, 0)
358
+}
359
+
360
+func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) {
361
+	if l.IsClosing() {
362
+		return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed"))
363
+	}
364
+	l.messageMutex.Lock()
365
+	l.Debug.Printf("flags&startTLS = %d", flags&startTLS)
366
+	if l.isStartingTLS {
367
+		l.messageMutex.Unlock()
368
+		return nil, NewError(ErrorNetwork, errors.New("ldap: connection is in startls phase"))
369
+	}
370
+	if flags&startTLS != 0 {
371
+		if l.outstandingRequests != 0 {
372
+			l.messageMutex.Unlock()
373
+			return nil, NewError(ErrorNetwork, errors.New("ldap: cannot StartTLS with outstanding requests"))
374
+		}
375
+		l.isStartingTLS = true
376
+	}
377
+	l.outstandingRequests++
378
+
379
+	l.messageMutex.Unlock()
380
+
381
+	responses := make(chan *PacketResponse)
382
+	messageID := packet.Children[0].Value.(int64)
383
+	message := &messagePacket{
384
+		Op:        MessageRequest,
385
+		MessageID: messageID,
386
+		Packet:    packet,
387
+		Context: &messageContext{
388
+			id:        messageID,
389
+			done:      make(chan struct{}),
390
+			responses: responses,
391
+		},
392
+	}
393
+	l.sendProcessMessage(message)
394
+	return message.Context, nil
395
+}
396
+
397
+func (l *Conn) finishMessage(msgCtx *messageContext) {
398
+	close(msgCtx.done)
399
+
400
+	if l.IsClosing() {
401
+		return
402
+	}
403
+
404
+	l.messageMutex.Lock()
405
+	l.outstandingRequests--
406
+	if l.isStartingTLS {
407
+		l.isStartingTLS = false
408
+	}
409
+	l.messageMutex.Unlock()
410
+
411
+	message := &messagePacket{
412
+		Op:        MessageFinish,
413
+		MessageID: msgCtx.id,
414
+	}
415
+	l.sendProcessMessage(message)
416
+}
417
+
418
+func (l *Conn) sendProcessMessage(message *messagePacket) bool {
419
+	l.messageMutex.Lock()
420
+	defer l.messageMutex.Unlock()
421
+	if l.IsClosing() {
422
+		return false
423
+	}
424
+	l.chanMessage <- message
425
+	return true
426
+}
427
+
428
+func (l *Conn) processMessages() {
429
+	defer func() {
430
+		if err := recover(); err != nil {
431
+			log.Printf("ldap: recovered panic in processMessages: %v", err)
432
+		}
433
+		for messageID, msgCtx := range l.messageContexts {
434
+			// If we are closing due to an error, inform anyone who
435
+			// is waiting about the error.
436
+			if l.IsClosing() && l.closeErr.Load() != nil {
437
+				msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)})
438
+			}
439
+			l.Debug.Printf("Closing channel for MessageID %d", messageID)
440
+			close(msgCtx.responses)
441
+			delete(l.messageContexts, messageID)
442
+		}
443
+		close(l.chanMessageID)
444
+		close(l.chanConfirm)
445
+	}()
446
+
447
+	var messageID int64 = 1
448
+	for {
449
+		select {
450
+		case l.chanMessageID <- messageID:
451
+			messageID++
452
+		case message := <-l.chanMessage:
453
+			switch message.Op {
454
+			case MessageQuit:
455
+				l.Debug.Printf("Shutting down - quit message received")
456
+				return
457
+			case MessageRequest:
458
+				// Add to message list and write to network
459
+				l.Debug.Printf("Sending message %d", message.MessageID)
460
+
461
+				buf := message.Packet.Bytes()
462
+				_, err := l.conn.Write(buf)
463
+				if err != nil {
464
+					l.Debug.Printf("Error Sending Message: %s", err.Error())
465
+					message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)})
466
+					close(message.Context.responses)
467
+					break
468
+				}
469
+
470
+				// Only add to messageContexts if we were able to
471
+				// successfully write the message.
472
+				l.messageContexts[message.MessageID] = message.Context
473
+
474
+				// Add timeout if defined
475
+				requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout))
476
+				if requestTimeout > 0 {
477
+					go func() {
478
+						defer func() {
479
+							if err := recover(); err != nil {
480
+								log.Printf("ldap: recovered panic in RequestTimeout: %v", err)
481
+							}
482
+						}()
483
+						time.Sleep(requestTimeout)
484
+						timeoutMessage := &messagePacket{
485
+							Op:        MessageTimeout,
486
+							MessageID: message.MessageID,
487
+						}
488
+						l.sendProcessMessage(timeoutMessage)
489
+					}()
490
+				}
491
+			case MessageResponse:
492
+				l.Debug.Printf("Receiving message %d", message.MessageID)
493
+				if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
494
+					msgCtx.sendResponse(&PacketResponse{message.Packet, nil})
495
+				} else {
496
+					log.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing())
497
+					l.Debug.PrintPacket(message.Packet)
498
+				}
499
+			case MessageTimeout:
500
+				// Handle the timeout by closing the channel
501
+				// All reads will return immediately
502
+				if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
503
+					l.Debug.Printf("Receiving message timeout for %d", message.MessageID)
504
+					msgCtx.sendResponse(&PacketResponse{message.Packet, errors.New("ldap: connection timed out")})
505
+					delete(l.messageContexts, message.MessageID)
506
+					close(msgCtx.responses)
507
+				}
508
+			case MessageFinish:
509
+				l.Debug.Printf("Finished message %d", message.MessageID)
510
+				if msgCtx, ok := l.messageContexts[message.MessageID]; ok {
511
+					delete(l.messageContexts, message.MessageID)
512
+					close(msgCtx.responses)
513
+				}
514
+			}
515
+		}
516
+	}
517
+}
518
+
519
+func (l *Conn) reader() {
520
+	cleanstop := false
521
+	defer func() {
522
+		if err := recover(); err != nil {
523
+			log.Printf("ldap: recovered panic in reader: %v", err)
524
+		}
525
+		if !cleanstop {
526
+			l.Close()
527
+		}
528
+	}()
529
+
530
+	for {
531
+		if cleanstop {
532
+			l.Debug.Printf("reader clean stopping (without closing the connection)")
533
+			return
534
+		}
535
+		packet, err := ber.ReadPacket(l.conn)
536
+		if err != nil {
537
+			// A read error is expected here if we are closing the connection...
538
+			if !l.IsClosing() {
539
+				l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err))
540
+				l.Debug.Printf("reader error: %s", err)
541
+			}
542
+			return
543
+		}
544
+		if err := addLDAPDescriptions(packet); err != nil {
545
+			l.Debug.Printf("descriptions error: %s", err)
546
+		}
547
+		if len(packet.Children) == 0 {
548
+			l.Debug.Printf("Received bad ldap packet")
549
+			continue
550
+		}
551
+		l.messageMutex.Lock()
552
+		if l.isStartingTLS {
553
+			cleanstop = true
554
+		}
555
+		l.messageMutex.Unlock()
556
+		message := &messagePacket{
557
+			Op:        MessageResponse,
558
+			MessageID: packet.Children[0].Value.(int64),
559
+			Packet:    packet,
560
+		}
561
+		if !l.sendProcessMessage(message) {
562
+			return
563
+		}
564
+	}
565
+}

+ 499
- 0
vendor/github.com/go-ldap/ldap/v3/control.go View File

@@ -0,0 +1,499 @@
1
+package ldap
2
+
3
+import (
4
+	"fmt"
5
+	"strconv"
6
+
7
+	"github.com/go-asn1-ber/asn1-ber"
8
+)
9
+
10
+const (
11
+	// ControlTypePaging - https://www.ietf.org/rfc/rfc2696.txt
12
+	ControlTypePaging = "1.2.840.113556.1.4.319"
13
+	// ControlTypeBeheraPasswordPolicy - https://tools.ietf.org/html/draft-behera-ldap-password-policy-10
14
+	ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1"
15
+	// ControlTypeVChuPasswordMustChange - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
16
+	ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4"
17
+	// ControlTypeVChuPasswordWarning - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
18
+	ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
19
+	// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
20
+	ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
21
+
22
+	// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
23
+	ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
24
+	// ControlTypeMicrosoftShowDeleted - https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
25
+	ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417"
26
+)
27
+
28
+// ControlTypeMap maps controls to text descriptions
29
+var ControlTypeMap = map[string]string{
30
+	ControlTypePaging:                "Paging",
31
+	ControlTypeBeheraPasswordPolicy:  "Password Policy - Behera Draft",
32
+	ControlTypeManageDsaIT:           "Manage DSA IT",
33
+	ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
34
+	ControlTypeMicrosoftShowDeleted:  "Show Deleted Objects - Microsoft",
35
+}
36
+
37
+// Control defines an interface controls provide to encode and describe themselves
38
+type Control interface {
39
+	// GetControlType returns the OID
40
+	GetControlType() string
41
+	// Encode returns the ber packet representation
42
+	Encode() *ber.Packet
43
+	// String returns a human-readable description
44
+	String() string
45
+}
46
+
47
+// ControlString implements the Control interface for simple controls
48
+type ControlString struct {
49
+	ControlType  string
50
+	Criticality  bool
51
+	ControlValue string
52
+}
53
+
54
+// GetControlType returns the OID
55
+func (c *ControlString) GetControlType() string {
56
+	return c.ControlType
57
+}
58
+
59
+// Encode returns the ber packet representation
60
+func (c *ControlString) Encode() *ber.Packet {
61
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
62
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")"))
63
+	if c.Criticality {
64
+		packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
65
+	}
66
+	if c.ControlValue != "" {
67
+		packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(c.ControlValue), "Control Value"))
68
+	}
69
+	return packet
70
+}
71
+
72
+// String returns a human-readable description
73
+func (c *ControlString) String() string {
74
+	return fmt.Sprintf("Control Type: %s (%q)  Criticality: %t  Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue)
75
+}
76
+
77
+// ControlPaging implements the paging control described in https://www.ietf.org/rfc/rfc2696.txt
78
+type ControlPaging struct {
79
+	// PagingSize indicates the page size
80
+	PagingSize uint32
81
+	// Cookie is an opaque value returned by the server to track a paging cursor
82
+	Cookie []byte
83
+}
84
+
85
+// GetControlType returns the OID
86
+func (c *ControlPaging) GetControlType() string {
87
+	return ControlTypePaging
88
+}
89
+
90
+// Encode returns the ber packet representation
91
+func (c *ControlPaging) Encode() *ber.Packet {
92
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
93
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")"))
94
+
95
+	p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)")
96
+	seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
97
+	seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.PagingSize), "Paging Size"))
98
+	cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
99
+	cookie.Value = c.Cookie
100
+	cookie.Data.Write(c.Cookie)
101
+	seq.AppendChild(cookie)
102
+	p2.AppendChild(seq)
103
+
104
+	packet.AppendChild(p2)
105
+	return packet
106
+}
107
+
108
+// String returns a human-readable description
109
+func (c *ControlPaging) String() string {
110
+	return fmt.Sprintf(
111
+		"Control Type: %s (%q)  Criticality: %t  PagingSize: %d  Cookie: %q",
112
+		ControlTypeMap[ControlTypePaging],
113
+		ControlTypePaging,
114
+		false,
115
+		c.PagingSize,
116
+		c.Cookie)
117
+}
118
+
119
+// SetCookie stores the given cookie in the paging control
120
+func (c *ControlPaging) SetCookie(cookie []byte) {
121
+	c.Cookie = cookie
122
+}
123
+
124
+// ControlBeheraPasswordPolicy implements the control described in https://tools.ietf.org/html/draft-behera-ldap-password-policy-10
125
+type ControlBeheraPasswordPolicy struct {
126
+	// Expire contains the number of seconds before a password will expire
127
+	Expire int64
128
+	// Grace indicates the remaining number of times a user will be allowed to authenticate with an expired password
129
+	Grace int64
130
+	// Error indicates the error code
131
+	Error int8
132
+	// ErrorString is a human readable error
133
+	ErrorString string
134
+}
135
+
136
+// GetControlType returns the OID
137
+func (c *ControlBeheraPasswordPolicy) GetControlType() string {
138
+	return ControlTypeBeheraPasswordPolicy
139
+}
140
+
141
+// Encode returns the ber packet representation
142
+func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet {
143
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
144
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeBeheraPasswordPolicy, "Control Type ("+ControlTypeMap[ControlTypeBeheraPasswordPolicy]+")"))
145
+
146
+	return packet
147
+}
148
+
149
+// String returns a human-readable description
150
+func (c *ControlBeheraPasswordPolicy) String() string {
151
+	return fmt.Sprintf(
152
+		"Control Type: %s (%q)  Criticality: %t  Expire: %d  Grace: %d  Error: %d, ErrorString: %s",
153
+		ControlTypeMap[ControlTypeBeheraPasswordPolicy],
154
+		ControlTypeBeheraPasswordPolicy,
155
+		false,
156
+		c.Expire,
157
+		c.Grace,
158
+		c.Error,
159
+		c.ErrorString)
160
+}
161
+
162
+// ControlVChuPasswordMustChange implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
163
+type ControlVChuPasswordMustChange struct {
164
+	// MustChange indicates if the password is required to be changed
165
+	MustChange bool
166
+}
167
+
168
+// GetControlType returns the OID
169
+func (c *ControlVChuPasswordMustChange) GetControlType() string {
170
+	return ControlTypeVChuPasswordMustChange
171
+}
172
+
173
+// Encode returns the ber packet representation
174
+func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet {
175
+	return nil
176
+}
177
+
178
+// String returns a human-readable description
179
+func (c *ControlVChuPasswordMustChange) String() string {
180
+	return fmt.Sprintf(
181
+		"Control Type: %s (%q)  Criticality: %t  MustChange: %v",
182
+		ControlTypeMap[ControlTypeVChuPasswordMustChange],
183
+		ControlTypeVChuPasswordMustChange,
184
+		false,
185
+		c.MustChange)
186
+}
187
+
188
+// ControlVChuPasswordWarning implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
189
+type ControlVChuPasswordWarning struct {
190
+	// Expire indicates the time in seconds until the password expires
191
+	Expire int64
192
+}
193
+
194
+// GetControlType returns the OID
195
+func (c *ControlVChuPasswordWarning) GetControlType() string {
196
+	return ControlTypeVChuPasswordWarning
197
+}
198
+
199
+// Encode returns the ber packet representation
200
+func (c *ControlVChuPasswordWarning) Encode() *ber.Packet {
201
+	return nil
202
+}
203
+
204
+// String returns a human-readable description
205
+func (c *ControlVChuPasswordWarning) String() string {
206
+	return fmt.Sprintf(
207
+		"Control Type: %s (%q)  Criticality: %t  Expire: %b",
208
+		ControlTypeMap[ControlTypeVChuPasswordWarning],
209
+		ControlTypeVChuPasswordWarning,
210
+		false,
211
+		c.Expire)
212
+}
213
+
214
+// ControlManageDsaIT implements the control described in https://tools.ietf.org/html/rfc3296
215
+type ControlManageDsaIT struct {
216
+	// Criticality indicates if this control is required
217
+	Criticality bool
218
+}
219
+
220
+// GetControlType returns the OID
221
+func (c *ControlManageDsaIT) GetControlType() string {
222
+	return ControlTypeManageDsaIT
223
+}
224
+
225
+// Encode returns the ber packet representation
226
+func (c *ControlManageDsaIT) Encode() *ber.Packet {
227
+	//FIXME
228
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
229
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeManageDsaIT, "Control Type ("+ControlTypeMap[ControlTypeManageDsaIT]+")"))
230
+	if c.Criticality {
231
+		packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
232
+	}
233
+	return packet
234
+}
235
+
236
+// String returns a human-readable description
237
+func (c *ControlManageDsaIT) String() string {
238
+	return fmt.Sprintf(
239
+		"Control Type: %s (%q)  Criticality: %t",
240
+		ControlTypeMap[ControlTypeManageDsaIT],
241
+		ControlTypeManageDsaIT,
242
+		c.Criticality)
243
+}
244
+
245
+// NewControlManageDsaIT returns a ControlManageDsaIT control
246
+func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
247
+	return &ControlManageDsaIT{Criticality: Criticality}
248
+}
249
+
250
+// ControlMicrosoftNotification implements the control described in https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
251
+type ControlMicrosoftNotification struct{}
252
+
253
+// GetControlType returns the OID
254
+func (c *ControlMicrosoftNotification) GetControlType() string {
255
+	return ControlTypeMicrosoftNotification
256
+}
257
+
258
+// Encode returns the ber packet representation
259
+func (c *ControlMicrosoftNotification) Encode() *ber.Packet {
260
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
261
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftNotification, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftNotification]+")"))
262
+
263
+	return packet
264
+}
265
+
266
+// String returns a human-readable description
267
+func (c *ControlMicrosoftNotification) String() string {
268
+	return fmt.Sprintf(
269
+		"Control Type: %s (%q)",
270
+		ControlTypeMap[ControlTypeMicrosoftNotification],
271
+		ControlTypeMicrosoftNotification)
272
+}
273
+
274
+// NewControlMicrosoftNotification returns a ControlMicrosoftNotification control
275
+func NewControlMicrosoftNotification() *ControlMicrosoftNotification {
276
+	return &ControlMicrosoftNotification{}
277
+}
278
+
279
+// ControlMicrosoftShowDeleted implements the control described in https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
280
+type ControlMicrosoftShowDeleted struct{}
281
+
282
+// GetControlType returns the OID
283
+func (c *ControlMicrosoftShowDeleted) GetControlType() string {
284
+	return ControlTypeMicrosoftShowDeleted
285
+}
286
+
287
+// Encode returns the ber packet representation
288
+func (c *ControlMicrosoftShowDeleted) Encode() *ber.Packet {
289
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
290
+	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftShowDeleted, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftShowDeleted]+")"))
291
+
292
+	return packet
293
+}
294
+
295
+// String returns a human-readable description
296
+func (c *ControlMicrosoftShowDeleted) String() string {
297
+	return fmt.Sprintf(
298
+		"Control Type: %s (%q)",
299
+		ControlTypeMap[ControlTypeMicrosoftShowDeleted],
300
+		ControlTypeMicrosoftShowDeleted)
301
+}
302
+
303
+// NewControlMicrosoftShowDeleted returns a ControlMicrosoftShowDeleted control
304
+func NewControlMicrosoftShowDeleted() *ControlMicrosoftShowDeleted {
305
+	return &ControlMicrosoftShowDeleted{}
306
+}
307
+
308
+// FindControl returns the first control of the given type in the list, or nil
309
+func FindControl(controls []Control, controlType string) Control {
310
+	for _, c := range controls {
311
+		if c.GetControlType() == controlType {
312
+			return c
313
+		}
314
+	}
315
+	return nil
316
+}
317
+
318
+// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
319
+func DecodeControl(packet *ber.Packet) (Control, error) {
320
+	var (
321
+		ControlType = ""
322
+		Criticality = false
323
+		value       *ber.Packet
324
+	)
325
+
326
+	switch len(packet.Children) {
327
+	case 0:
328
+		// at least one child is required for control type
329
+		return nil, fmt.Errorf("at least one child is required for control type")
330
+
331
+	case 1:
332
+		// just type, no criticality or value
333
+		packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
334
+		ControlType = packet.Children[0].Value.(string)
335
+
336
+	case 2:
337
+		packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
338
+		ControlType = packet.Children[0].Value.(string)
339
+
340
+		// Children[1] could be criticality or value (both are optional)
341
+		// duck-type on whether this is a boolean
342
+		if _, ok := packet.Children[1].Value.(bool); ok {
343
+			packet.Children[1].Description = "Criticality"
344
+			Criticality = packet.Children[1].Value.(bool)
345
+		} else {
346
+			packet.Children[1].Description = "Control Value"
347
+			value = packet.Children[1]
348
+		}
349
+
350
+	case 3:
351
+		packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
352
+		ControlType = packet.Children[0].Value.(string)
353
+
354
+		packet.Children[1].Description = "Criticality"
355
+		Criticality = packet.Children[1].Value.(bool)
356
+
357
+		packet.Children[2].Description = "Control Value"
358
+		value = packet.Children[2]
359
+
360
+	default:
361
+		// more than 3 children is invalid
362
+		return nil, fmt.Errorf("more than 3 children is invalid for controls")
363
+	}
364
+
365
+	switch ControlType {
366
+	case ControlTypeManageDsaIT:
367
+		return NewControlManageDsaIT(Criticality), nil
368
+	case ControlTypePaging:
369
+		value.Description += " (Paging)"
370
+		c := new(ControlPaging)
371
+		if value.Value != nil {
372
+			valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
373
+			if err != nil {
374
+				return nil, fmt.Errorf("failed to decode data bytes: %s", err)
375
+			}
376
+			value.Data.Truncate(0)
377
+			value.Value = nil
378
+			value.AppendChild(valueChildren)
379
+		}
380
+		value = value.Children[0]
381
+		value.Description = "Search Control Value"
382
+		value.Children[0].Description = "Paging Size"
383
+		value.Children[1].Description = "Cookie"
384
+		c.PagingSize = uint32(value.Children[0].Value.(int64))
385
+		c.Cookie = value.Children[1].Data.Bytes()
386
+		value.Children[1].Value = c.Cookie
387
+		return c, nil
388
+	case ControlTypeBeheraPasswordPolicy:
389
+		value.Description += " (Password Policy - Behera)"
390
+		c := NewControlBeheraPasswordPolicy()
391
+		if value.Value != nil {
392
+			valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
393
+			if err != nil {
394
+				return nil, fmt.Errorf("failed to decode data bytes: %s", err)
395
+			}
396
+			value.Data.Truncate(0)
397
+			value.Value = nil
398
+			value.AppendChild(valueChildren)
399
+		}
400
+
401
+		sequence := value.Children[0]
402
+
403
+		for _, child := range sequence.Children {
404
+			if child.Tag == 0 {
405
+				//Warning
406
+				warningPacket := child.Children[0]
407
+				packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
408
+				if err != nil {
409
+					return nil, fmt.Errorf("failed to decode data bytes: %s", err)
410
+				}
411
+				val, ok := packet.Value.(int64)
412
+				if ok {
413
+					if warningPacket.Tag == 0 {
414
+						//timeBeforeExpiration
415
+						c.Expire = val
416
+						warningPacket.Value = c.Expire
417
+					} else if warningPacket.Tag == 1 {
418
+						//graceAuthNsRemaining
419
+						c.Grace = val
420
+						warningPacket.Value = c.Grace
421
+					}
422
+				}
423
+			} else if child.Tag == 1 {
424
+				// Error
425
+				packet, err := ber.DecodePacketErr(child.Data.Bytes())
426
+				if err != nil {
427
+					return nil, fmt.Errorf("failed to decode data bytes: %s", err)
428
+				}
429
+				val, ok := packet.Value.(int8)
430
+				if !ok {
431
+					// what to do?
432
+					val = -1
433
+				}
434
+				c.Error = val
435
+				child.Value = c.Error
436
+				c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
437
+			}
438
+		}
439
+		return c, nil
440
+	case ControlTypeVChuPasswordMustChange:
441
+		c := &ControlVChuPasswordMustChange{MustChange: true}
442
+		return c, nil
443
+	case ControlTypeVChuPasswordWarning:
444
+		c := &ControlVChuPasswordWarning{Expire: -1}
445
+		expireStr := ber.DecodeString(value.Data.Bytes())
446
+
447
+		expire, err := strconv.ParseInt(expireStr, 10, 64)
448
+		if err != nil {
449
+			return nil, fmt.Errorf("failed to parse value as int: %s", err)
450
+		}
451
+		c.Expire = expire
452
+		value.Value = c.Expire
453
+
454
+		return c, nil
455
+	case ControlTypeMicrosoftNotification:
456
+		return NewControlMicrosoftNotification(), nil
457
+	case ControlTypeMicrosoftShowDeleted:
458
+		return NewControlMicrosoftShowDeleted(), nil
459
+	default:
460
+		c := new(ControlString)
461
+		c.ControlType = ControlType
462
+		c.Criticality = Criticality
463
+		if value != nil {
464
+			c.ControlValue = value.Value.(string)
465
+		}
466
+		return c, nil
467
+	}
468
+}
469
+
470
+// NewControlString returns a generic control
471
+func NewControlString(controlType string, criticality bool, controlValue string) *ControlString {
472
+	return &ControlString{
473
+		ControlType:  controlType,
474
+		Criticality:  criticality,
475
+		ControlValue: controlValue,
476
+	}
477
+}
478
+
479
+// NewControlPaging returns a paging control
480
+func NewControlPaging(pagingSize uint32) *ControlPaging {
481
+	return &ControlPaging{PagingSize: pagingSize}
482
+}
483
+
484
+// NewControlBeheraPasswordPolicy returns a ControlBeheraPasswordPolicy
485
+func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy {
486
+	return &ControlBeheraPasswordPolicy{
487
+		Expire: -1,
488
+		Grace:  -1,
489
+		Error:  -1,
490
+	}
491
+}
492
+
493
+func encodeControls(controls []Control) *ber.Packet {
494
+	packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
495
+	for _, control := range controls {
496
+		packet.AppendChild(control.Encode())
497
+	}
498
+	return packet
499
+}

+ 30
- 0
vendor/github.com/go-ldap/ldap/v3/debug.go View File

@@ -0,0 +1,30 @@
1
+package ldap
2
+
3
+import (
4
+	"log"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// debugging type
10
+//     - has a Printf method to write the debug output
11
+type debugging bool
12
+
13
+// Enable controls debugging mode.
14
+func (debug *debugging) Enable(b bool) {
15
+	*debug = debugging(b)
16
+}
17
+
18
+// Printf writes debug output.
19
+func (debug debugging) Printf(format string, args ...interface{}) {
20
+	if debug {
21
+		log.Printf(format, args...)
22
+	}
23
+}
24
+
25
+// PrintPacket dumps a packet.
26
+func (debug debugging) PrintPacket(packet *ber.Packet) {
27
+	if debug {
28
+		ber.PrintPacket(packet)
29
+	}
30
+}

+ 59
- 0
vendor/github.com/go-ldap/ldap/v3/del.go View File

@@ -0,0 +1,59 @@
1
+package ldap
2
+
3
+import (
4
+	"log"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// DelRequest implements an LDAP deletion request
10
+type DelRequest struct {
11
+	// DN is the name of the directory entry to delete
12
+	DN string
13
+	// Controls hold optional controls to send with the request
14
+	Controls []Control
15
+}
16
+
17
+func (req *DelRequest) appendTo(envelope *ber.Packet) error {
18
+	pkt := ber.Encode(ber.ClassApplication, ber.TypePrimitive, ApplicationDelRequest, req.DN, "Del Request")
19
+	pkt.Data.Write([]byte(req.DN))
20
+
21
+	envelope.AppendChild(pkt)
22
+	if len(req.Controls) > 0 {
23
+		envelope.AppendChild(encodeControls(req.Controls))
24
+	}
25
+
26
+	return nil
27
+}
28
+
29
+// NewDelRequest creates a delete request for the given DN and controls
30
+func NewDelRequest(DN string, Controls []Control) *DelRequest {
31
+	return &DelRequest{
32
+		DN:       DN,
33
+		Controls: Controls,
34
+	}
35
+}
36
+
37
+// Del executes the given delete request
38
+func (l *Conn) Del(delRequest *DelRequest) error {
39
+	msgCtx, err := l.doRequest(delRequest)
40
+	if err != nil {
41
+		return err
42
+	}
43
+	defer l.finishMessage(msgCtx)
44
+
45
+	packet, err := l.readPacket(msgCtx)
46
+	if err != nil {
47
+		return err
48
+	}
49
+
50
+	if packet.Children[1].Tag == ApplicationDelResponse {
51
+		err := GetLDAPError(packet)
52
+		if err != nil {
53
+			return err
54
+		}
55
+	} else {
56
+		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
57
+	}
58
+	return nil
59
+}

+ 207
- 0
vendor/github.com/go-ldap/ldap/v3/dn.go View File

@@ -0,0 +1,207 @@
1
+package ldap
2
+
3
+import (
4
+	"bytes"
5
+	enchex "encoding/hex"
6
+	"errors"
7
+	"fmt"
8
+	"strings"
9
+
10
+	ber "github.com/go-asn1-ber/asn1-ber"
11
+)
12
+
13
+// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514
14
+type AttributeTypeAndValue struct {
15
+	// Type is the attribute type
16
+	Type string
17
+	// Value is the attribute value
18
+	Value string
19
+}
20
+
21
+// RelativeDN represents a relativeDistinguishedName from https://tools.ietf.org/html/rfc4514
22
+type RelativeDN struct {
23
+	Attributes []*AttributeTypeAndValue
24
+}
25
+
26
+// DN represents a distinguishedName from https://tools.ietf.org/html/rfc4514
27
+type DN struct {
28
+	RDNs []*RelativeDN
29
+}
30
+
31
+// ParseDN returns a distinguishedName or an error.
32
+// The function respects https://tools.ietf.org/html/rfc4514
33
+func ParseDN(str string) (*DN, error) {
34
+	dn := new(DN)
35
+	dn.RDNs = make([]*RelativeDN, 0)
36
+	rdn := new(RelativeDN)
37
+	rdn.Attributes = make([]*AttributeTypeAndValue, 0)
38
+	buffer := bytes.Buffer{}
39
+	attribute := new(AttributeTypeAndValue)
40
+	escaping := false
41
+
42
+	unescapedTrailingSpaces := 0
43
+	stringFromBuffer := func() string {
44
+		s := buffer.String()
45
+		s = s[0 : len(s)-unescapedTrailingSpaces]
46
+		buffer.Reset()
47
+		unescapedTrailingSpaces = 0
48
+		return s
49
+	}
50
+
51
+	for i := 0; i < len(str); i++ {
52
+		char := str[i]
53
+		switch {
54
+		case escaping:
55
+			unescapedTrailingSpaces = 0
56
+			escaping = false
57
+			switch char {
58
+			case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\':
59
+				buffer.WriteByte(char)
60
+				continue
61
+			}
62
+			// Not a special character, assume hex encoded octet
63
+			if len(str) == i+1 {
64
+				return nil, errors.New("got corrupted escaped character")
65
+			}
66
+
67
+			dst := []byte{0}
68
+			n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
69
+			if err != nil {
70
+				return nil, fmt.Errorf("failed to decode escaped character: %s", err)
71
+			} else if n != 1 {
72
+				return nil, fmt.Errorf("expected 1 byte when un-escaping, got %d", n)
73
+			}
74
+			buffer.WriteByte(dst[0])
75
+			i++
76
+		case char == '\\':
77
+			unescapedTrailingSpaces = 0
78
+			escaping = true
79
+		case char == '=':
80
+			attribute.Type = stringFromBuffer()
81
+			// Special case: If the first character in the value is # the
82
+			// following data is BER encoded so we can just fast forward
83
+			// and decode.
84
+			if len(str) > i+1 && str[i+1] == '#' {
85
+				i += 2
86
+				index := strings.IndexAny(str[i:], ",+")
87
+				data := str
88
+				if index > 0 {
89
+					data = str[i : i+index]
90
+				} else {
91
+					data = str[i:]
92
+				}
93
+				rawBER, err := enchex.DecodeString(data)
94
+				if err != nil {
95
+					return nil, fmt.Errorf("failed to decode BER encoding: %s", err)
96
+				}
97
+				packet, err := ber.DecodePacketErr(rawBER)
98
+				if err != nil {
99
+					return nil, fmt.Errorf("failed to decode BER packet: %s", err)
100
+				}
101
+				buffer.WriteString(packet.Data.String())
102
+				i += len(data) - 1
103
+			}
104
+		case char == ',' || char == '+':
105
+			// We're done with this RDN or value, push it
106
+			if len(attribute.Type) == 0 {
107
+				return nil, errors.New("incomplete type, value pair")
108
+			}
109
+			attribute.Value = stringFromBuffer()
110
+			rdn.Attributes = append(rdn.Attributes, attribute)
111
+			attribute = new(AttributeTypeAndValue)
112
+			if char == ',' {
113
+				dn.RDNs = append(dn.RDNs, rdn)
114
+				rdn = new(RelativeDN)
115
+				rdn.Attributes = make([]*AttributeTypeAndValue, 0)
116
+			}
117
+		case char == ' ' && buffer.Len() == 0:
118
+			// ignore unescaped leading spaces
119
+			continue
120
+		default:
121
+			if char == ' ' {
122
+				// Track unescaped spaces in case they are trailing and we need to remove them
123
+				unescapedTrailingSpaces++
124
+			} else {
125
+				// Reset if we see a non-space char
126
+				unescapedTrailingSpaces = 0
127
+			}
128
+			buffer.WriteByte(char)
129
+		}
130
+	}
131
+	if buffer.Len() > 0 {
132
+		if len(attribute.Type) == 0 {
133
+			return nil, errors.New("DN ended with incomplete type, value pair")
134
+		}
135
+		attribute.Value = stringFromBuffer()
136
+		rdn.Attributes = append(rdn.Attributes, attribute)
137
+		dn.RDNs = append(dn.RDNs, rdn)
138
+	}
139
+	return dn, nil
140
+}
141
+
142
+// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
143
+// Returns true if they have the same number of relative distinguished names
144
+// and corresponding relative distinguished names (by position) are the same.
145
+func (d *DN) Equal(other *DN) bool {
146
+	if len(d.RDNs) != len(other.RDNs) {
147
+		return false
148
+	}
149
+	for i := range d.RDNs {
150
+		if !d.RDNs[i].Equal(other.RDNs[i]) {
151
+			return false
152
+		}
153
+	}
154
+	return true
155
+}
156
+
157
+// AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN.
158
+// "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com"
159
+// "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com"
160
+// "ou=widgets,o=acme.com" is not an ancestor of "ou=widgets,o=acme.com"
161
+func (d *DN) AncestorOf(other *DN) bool {
162
+	if len(d.RDNs) >= len(other.RDNs) {
163
+		return false
164
+	}
165
+	// Take the last `len(d.RDNs)` RDNs from the other DN to compare against
166
+	otherRDNs := other.RDNs[len(other.RDNs)-len(d.RDNs):]
167
+	for i := range d.RDNs {
168
+		if !d.RDNs[i].Equal(otherRDNs[i]) {
169
+			return false
170
+		}
171
+	}
172
+	return true
173
+}
174
+
175
+// Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
176
+// Relative distinguished names are the same if and only if they have the same number of AttributeTypeAndValues
177
+// and each attribute of the first RDN is the same as the attribute of the second RDN with the same attribute type.
178
+// The order of attributes is not significant.
179
+// Case of attribute types is not significant.
180
+func (r *RelativeDN) Equal(other *RelativeDN) bool {
181
+	if len(r.Attributes) != len(other.Attributes) {
182
+		return false
183
+	}
184
+	return r.hasAllAttributes(other.Attributes) && other.hasAllAttributes(r.Attributes)
185
+}
186
+
187
+func (r *RelativeDN) hasAllAttributes(attrs []*AttributeTypeAndValue) bool {
188
+	for _, attr := range attrs {
189
+		found := false
190
+		for _, myattr := range r.Attributes {
191
+			if myattr.Equal(attr) {
192
+				found = true
193
+				break
194
+			}
195
+		}
196
+		if !found {
197
+			return false
198
+		}
199
+	}
200
+	return true
201
+}
202
+
203
+// Equal returns true if the AttributeTypeAndValue is equivalent to the specified AttributeTypeAndValue
204
+// Case of the attribute type is not significant
205
+func (a *AttributeTypeAndValue) Equal(other *AttributeTypeAndValue) bool {
206
+	return strings.EqualFold(a.Type, other.Type) && a.Value == other.Value
207
+}

+ 4
- 0
vendor/github.com/go-ldap/ldap/v3/doc.go View File

@@ -0,0 +1,4 @@
1
+/*
2
+Package ldap provides basic LDAP v3 functionality.
3
+*/
4
+package ldap

+ 236
- 0
vendor/github.com/go-ldap/ldap/v3/error.go View File

@@ -0,0 +1,236 @@
1
+package ldap
2
+
3
+import (
4
+	"fmt"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// LDAP Result Codes
10
+const (
11
+	LDAPResultSuccess                            = 0
12
+	LDAPResultOperationsError                    = 1
13
+	LDAPResultProtocolError                      = 2
14
+	LDAPResultTimeLimitExceeded                  = 3
15
+	LDAPResultSizeLimitExceeded                  = 4
16
+	LDAPResultCompareFalse                       = 5
17
+	LDAPResultCompareTrue                        = 6
18
+	LDAPResultAuthMethodNotSupported             = 7
19
+	LDAPResultStrongAuthRequired                 = 8
20
+	LDAPResultReferral                           = 10
21
+	LDAPResultAdminLimitExceeded                 = 11
22
+	LDAPResultUnavailableCriticalExtension       = 12
23
+	LDAPResultConfidentialityRequired            = 13
24
+	LDAPResultSaslBindInProgress                 = 14
25
+	LDAPResultNoSuchAttribute                    = 16
26
+	LDAPResultUndefinedAttributeType             = 17
27
+	LDAPResultInappropriateMatching              = 18
28
+	LDAPResultConstraintViolation                = 19
29
+	LDAPResultAttributeOrValueExists             = 20
30
+	LDAPResultInvalidAttributeSyntax             = 21
31
+	LDAPResultNoSuchObject                       = 32
32
+	LDAPResultAliasProblem                       = 33
33
+	LDAPResultInvalidDNSyntax                    = 34
34
+	LDAPResultIsLeaf                             = 35
35
+	LDAPResultAliasDereferencingProblem          = 36
36
+	LDAPResultInappropriateAuthentication        = 48
37
+	LDAPResultInvalidCredentials                 = 49
38
+	LDAPResultInsufficientAccessRights           = 50
39
+	LDAPResultBusy                               = 51
40
+	LDAPResultUnavailable                        = 52
41
+	LDAPResultUnwillingToPerform                 = 53
42
+	LDAPResultLoopDetect                         = 54
43
+	LDAPResultSortControlMissing                 = 60
44
+	LDAPResultOffsetRangeError                   = 61
45
+	LDAPResultNamingViolation                    = 64
46
+	LDAPResultObjectClassViolation               = 65
47
+	LDAPResultNotAllowedOnNonLeaf                = 66
48
+	LDAPResultNotAllowedOnRDN                    = 67
49
+	LDAPResultEntryAlreadyExists                 = 68
50
+	LDAPResultObjectClassModsProhibited          = 69
51
+	LDAPResultResultsTooLarge                    = 70
52
+	LDAPResultAffectsMultipleDSAs                = 71
53
+	LDAPResultVirtualListViewErrorOrControlError = 76
54
+	LDAPResultOther                              = 80
55
+	LDAPResultServerDown                         = 81
56
+	LDAPResultLocalError                         = 82
57
+	LDAPResultEncodingError                      = 83
58
+	LDAPResultDecodingError                      = 84
59
+	LDAPResultTimeout                            = 85
60
+	LDAPResultAuthUnknown                        = 86
61
+	LDAPResultFilterError                        = 87
62
+	LDAPResultUserCanceled                       = 88
63
+	LDAPResultParamError                         = 89
64
+	LDAPResultNoMemory                           = 90
65
+	LDAPResultConnectError                       = 91
66
+	LDAPResultNotSupported                       = 92
67
+	LDAPResultControlNotFound                    = 93
68
+	LDAPResultNoResultsReturned                  = 94
69
+	LDAPResultMoreResultsToReturn                = 95
70
+	LDAPResultClientLoop                         = 96
71
+	LDAPResultReferralLimitExceeded              = 97
72
+	LDAPResultInvalidResponse                    = 100
73
+	LDAPResultAmbiguousResponse                  = 101
74
+	LDAPResultTLSNotSupported                    = 112
75
+	LDAPResultIntermediateResponse               = 113
76
+	LDAPResultUnknownType                        = 114
77
+	LDAPResultCanceled                           = 118
78
+	LDAPResultNoSuchOperation                    = 119
79
+	LDAPResultTooLate                            = 120
80
+	LDAPResultCannotCancel                       = 121
81
+	LDAPResultAssertionFailed                    = 122
82
+	LDAPResultAuthorizationDenied                = 123
83
+	LDAPResultSyncRefreshRequired                = 4096
84
+
85
+	ErrorNetwork            = 200
86
+	ErrorFilterCompile      = 201
87
+	ErrorFilterDecompile    = 202
88
+	ErrorDebugging          = 203
89
+	ErrorUnexpectedMessage  = 204
90
+	ErrorUnexpectedResponse = 205
91
+	ErrorEmptyPassword      = 206
92
+)
93
+
94
+// LDAPResultCodeMap contains string descriptions for LDAP error codes
95
+var LDAPResultCodeMap = map[uint16]string{
96
+	LDAPResultSuccess:                            "Success",
97
+	LDAPResultOperationsError:                    "Operations Error",
98
+	LDAPResultProtocolError:                      "Protocol Error",
99
+	LDAPResultTimeLimitExceeded:                  "Time Limit Exceeded",
100
+	LDAPResultSizeLimitExceeded:                  "Size Limit Exceeded",
101
+	LDAPResultCompareFalse:                       "Compare False",
102
+	LDAPResultCompareTrue:                        "Compare True",
103
+	LDAPResultAuthMethodNotSupported:             "Auth Method Not Supported",
104
+	LDAPResultStrongAuthRequired:                 "Strong Auth Required",
105
+	LDAPResultReferral:                           "Referral",
106
+	LDAPResultAdminLimitExceeded:                 "Admin Limit Exceeded",
107
+	LDAPResultUnavailableCriticalExtension:       "Unavailable Critical Extension",
108
+	LDAPResultConfidentialityRequired:            "Confidentiality Required",
109
+	LDAPResultSaslBindInProgress:                 "Sasl Bind In Progress",
110
+	LDAPResultNoSuchAttribute:                    "No Such Attribute",
111
+	LDAPResultUndefinedAttributeType:             "Undefined Attribute Type",
112
+	LDAPResultInappropriateMatching:              "Inappropriate Matching",
113
+	LDAPResultConstraintViolation:                "Constraint Violation",
114
+	LDAPResultAttributeOrValueExists:             "Attribute Or Value Exists",
115
+	LDAPResultInvalidAttributeSyntax:             "Invalid Attribute Syntax",
116
+	LDAPResultNoSuchObject:                       "No Such Object",
117
+	LDAPResultAliasProblem:                       "Alias Problem",
118
+	LDAPResultInvalidDNSyntax:                    "Invalid DN Syntax",
119
+	LDAPResultIsLeaf:                             "Is Leaf",
120
+	LDAPResultAliasDereferencingProblem:          "Alias Dereferencing Problem",
121
+	LDAPResultInappropriateAuthentication:        "Inappropriate Authentication",
122
+	LDAPResultInvalidCredentials:                 "Invalid Credentials",
123
+	LDAPResultInsufficientAccessRights:           "Insufficient Access Rights",
124
+	LDAPResultBusy:                               "Busy",
125
+	LDAPResultUnavailable:                        "Unavailable",
126
+	LDAPResultUnwillingToPerform:                 "Unwilling To Perform",
127
+	LDAPResultLoopDetect:                         "Loop Detect",
128
+	LDAPResultSortControlMissing:                 "Sort Control Missing",
129
+	LDAPResultOffsetRangeError:                   "Result Offset Range Error",
130
+	LDAPResultNamingViolation:                    "Naming Violation",
131
+	LDAPResultObjectClassViolation:               "Object Class Violation",
132
+	LDAPResultResultsTooLarge:                    "Results Too Large",
133
+	LDAPResultNotAllowedOnNonLeaf:                "Not Allowed On Non Leaf",
134
+	LDAPResultNotAllowedOnRDN:                    "Not Allowed On RDN",
135
+	LDAPResultEntryAlreadyExists:                 "Entry Already Exists",
136
+	LDAPResultObjectClassModsProhibited:          "Object Class Mods Prohibited",
137
+	LDAPResultAffectsMultipleDSAs:                "Affects Multiple DSAs",
138
+	LDAPResultVirtualListViewErrorOrControlError: "Failed because of a problem related to the virtual list view",
139
+	LDAPResultOther:                              "Other",
140
+	LDAPResultServerDown:                         "Cannot establish a connection",
141
+	LDAPResultLocalError:                         "An error occurred",
142
+	LDAPResultEncodingError:                      "LDAP encountered an error while encoding",
143
+	LDAPResultDecodingError:                      "LDAP encountered an error while decoding",
144
+	LDAPResultTimeout:                            "LDAP timeout while waiting for a response from the server",
145
+	LDAPResultAuthUnknown:                        "The auth method requested in a bind request is unknown",
146
+	LDAPResultFilterError:                        "An error occurred while encoding the given search filter",
147
+	LDAPResultUserCanceled:                       "The user canceled the operation",
148
+	LDAPResultParamError:                         "An invalid parameter was specified",
149
+	LDAPResultNoMemory:                           "Out of memory error",
150
+	LDAPResultConnectError:                       "A connection to the server could not be established",
151
+	LDAPResultNotSupported:                       "An attempt has been made to use a feature not supported LDAP",
152
+	LDAPResultControlNotFound:                    "The controls required to perform the requested operation were not found",
153
+	LDAPResultNoResultsReturned:                  "No results were returned from the server",
154
+	LDAPResultMoreResultsToReturn:                "There are more results in the chain of results",
155
+	LDAPResultClientLoop:                         "A loop has been detected. For example when following referrals",
156
+	LDAPResultReferralLimitExceeded:              "The referral hop limit has been exceeded",
157
+	LDAPResultCanceled:                           "Operation was canceled",
158
+	LDAPResultNoSuchOperation:                    "Server has no knowledge of the operation requested for cancellation",
159
+	LDAPResultTooLate:                            "Too late to cancel the outstanding operation",
160
+	LDAPResultCannotCancel:                       "The identified operation does not support cancellation or the cancel operation cannot be performed",
161
+	LDAPResultAssertionFailed:                    "An assertion control given in the LDAP operation evaluated to false causing the operation to not be performed",
162
+	LDAPResultSyncRefreshRequired:                "Refresh Required",
163
+	LDAPResultInvalidResponse:                    "Invalid Response",
164
+	LDAPResultAmbiguousResponse:                  "Ambiguous Response",
165
+	LDAPResultTLSNotSupported:                    "Tls Not Supported",
166
+	LDAPResultIntermediateResponse:               "Intermediate Response",
167
+	LDAPResultUnknownType:                        "Unknown Type",
168
+	LDAPResultAuthorizationDenied:                "Authorization Denied",
169
+
170
+	ErrorNetwork:            "Network Error",
171
+	ErrorFilterCompile:      "Filter Compile Error",
172
+	ErrorFilterDecompile:    "Filter Decompile Error",
173
+	ErrorDebugging:          "Debugging Error",
174
+	ErrorUnexpectedMessage:  "Unexpected Message",
175
+	ErrorUnexpectedResponse: "Unexpected Response",
176
+	ErrorEmptyPassword:      "Empty password not allowed by the client",
177
+}
178
+
179
+// Error holds LDAP error information
180
+type Error struct {
181
+	// Err is the underlying error
182
+	Err error
183
+	// ResultCode is the LDAP error code
184
+	ResultCode uint16
185
+	// MatchedDN is the matchedDN returned if any
186
+	MatchedDN string
187
+}
188
+
189
+func (e *Error) Error() string {
190
+	return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
191
+}
192
+
193
+// GetLDAPError creates an Error out of a BER packet representing a LDAPResult
194
+// The return is an error object. It can be casted to a Error structure.
195
+// This function returns nil if resultCode in the LDAPResult sequence is success(0).
196
+func GetLDAPError(packet *ber.Packet) error {
197
+	if packet == nil {
198
+		return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty packet")}
199
+	}
200
+
201
+	if len(packet.Children) >= 2 {
202
+		response := packet.Children[1]
203
+		if response == nil {
204
+			return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")}
205
+		}
206
+		if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
207
+			resultCode := uint16(response.Children[0].Value.(int64))
208
+			if resultCode == 0 { // No error
209
+				return nil
210
+			}
211
+			return &Error{ResultCode: resultCode, MatchedDN: response.Children[1].Value.(string),
212
+				Err: fmt.Errorf("%s", response.Children[2].Value.(string))}
213
+		}
214
+	}
215
+
216
+	return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format")}
217
+}
218
+
219
+// NewError creates an LDAP error with the given code and underlying error
220
+func NewError(resultCode uint16, err error) error {
221
+	return &Error{ResultCode: resultCode, Err: err}
222
+}
223
+
224
+// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
225
+func IsErrorWithCode(err error, desiredResultCode uint16) bool {
226
+	if err == nil {
227
+		return false
228
+	}
229
+
230
+	serverError, ok := err.(*Error)
231
+	if !ok {
232
+		return false
233
+	}
234
+
235
+	return serverError.ResultCode == desiredResultCode
236
+}

+ 487
- 0
vendor/github.com/go-ldap/ldap/v3/filter.go View File

@@ -0,0 +1,487 @@
1
+package ldap
2
+
3
+import (
4
+	"bytes"
5
+	hexpac "encoding/hex"
6
+	"errors"
7
+	"fmt"
8
+	"io"
9
+	"strings"
10
+	"unicode"
11
+	"unicode/utf8"
12
+
13
+	ber "github.com/go-asn1-ber/asn1-ber"
14
+)
15
+
16
+// Filter choices
17
+const (
18
+	FilterAnd             = 0
19
+	FilterOr              = 1
20
+	FilterNot             = 2
21
+	FilterEqualityMatch   = 3
22
+	FilterSubstrings      = 4
23
+	FilterGreaterOrEqual  = 5
24
+	FilterLessOrEqual     = 6
25
+	FilterPresent         = 7
26
+	FilterApproxMatch     = 8
27
+	FilterExtensibleMatch = 9
28
+)
29
+
30
+// FilterMap contains human readable descriptions of Filter choices
31
+var FilterMap = map[uint64]string{
32
+	FilterAnd:             "And",
33
+	FilterOr:              "Or",
34
+	FilterNot:             "Not",
35
+	FilterEqualityMatch:   "Equality Match",
36
+	FilterSubstrings:      "Substrings",
37
+	FilterGreaterOrEqual:  "Greater Or Equal",
38
+	FilterLessOrEqual:     "Less Or Equal",
39
+	FilterPresent:         "Present",
40
+	FilterApproxMatch:     "Approx Match",
41
+	FilterExtensibleMatch: "Extensible Match",
42
+}
43
+
44
+// SubstringFilter options
45
+const (
46
+	FilterSubstringsInitial = 0
47
+	FilterSubstringsAny     = 1
48
+	FilterSubstringsFinal   = 2
49
+)
50
+
51
+// FilterSubstringsMap contains human readable descriptions of SubstringFilter choices
52
+var FilterSubstringsMap = map[uint64]string{
53
+	FilterSubstringsInitial: "Substrings Initial",
54
+	FilterSubstringsAny:     "Substrings Any",
55
+	FilterSubstringsFinal:   "Substrings Final",
56
+}
57
+
58
+// MatchingRuleAssertion choices
59
+const (
60
+	MatchingRuleAssertionMatchingRule = 1
61
+	MatchingRuleAssertionType         = 2
62
+	MatchingRuleAssertionMatchValue   = 3
63
+	MatchingRuleAssertionDNAttributes = 4
64
+)
65
+
66
+// MatchingRuleAssertionMap contains human readable descriptions of MatchingRuleAssertion choices
67
+var MatchingRuleAssertionMap = map[uint64]string{
68
+	MatchingRuleAssertionMatchingRule: "Matching Rule Assertion Matching Rule",
69
+	MatchingRuleAssertionType:         "Matching Rule Assertion Type",
70
+	MatchingRuleAssertionMatchValue:   "Matching Rule Assertion Match Value",
71
+	MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes",
72
+}
73
+
74
+var _SymbolAny = []byte{'*'}
75
+
76
+// CompileFilter converts a string representation of a filter into a BER-encoded packet
77
+func CompileFilter(filter string) (*ber.Packet, error) {
78
+	if len(filter) == 0 || filter[0] != '(' {
79
+		return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('"))
80
+	}
81
+	packet, pos, err := compileFilter(filter, 1)
82
+	if err != nil {
83
+		return nil, err
84
+	}
85
+	switch {
86
+	case pos > len(filter):
87
+		return nil, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
88
+	case pos < len(filter):
89
+		return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:])))
90
+	}
91
+	return packet, nil
92
+}
93
+
94
+// DecompileFilter converts a packet representation of a filter into a string representation
95
+func DecompileFilter(packet *ber.Packet) (_ string, err error) {
96
+	defer func() {
97
+		if r := recover(); r != nil {
98
+			err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter"))
99
+		}
100
+	}()
101
+
102
+	buf := bytes.NewBuffer(nil)
103
+	buf.WriteByte('(')
104
+	childStr := ""
105
+
106
+	switch packet.Tag {
107
+	case FilterAnd:
108
+		buf.WriteByte('&')
109
+		for _, child := range packet.Children {
110
+			childStr, err = DecompileFilter(child)
111
+			if err != nil {
112
+				return
113
+			}
114
+			buf.WriteString(childStr)
115
+		}
116
+	case FilterOr:
117
+		buf.WriteByte('|')
118
+		for _, child := range packet.Children {
119
+			childStr, err = DecompileFilter(child)
120
+			if err != nil {
121
+				return
122
+			}
123
+			buf.WriteString(childStr)
124
+		}
125
+	case FilterNot:
126
+		buf.WriteByte('!')
127
+		childStr, err = DecompileFilter(packet.Children[0])
128
+		if err != nil {
129
+			return
130
+		}
131
+		buf.WriteString(childStr)
132
+
133
+	case FilterSubstrings:
134
+		buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
135
+		buf.WriteByte('=')
136
+		for i, child := range packet.Children[1].Children {
137
+			if i == 0 && child.Tag != FilterSubstringsInitial {
138
+				buf.Write(_SymbolAny)
139
+			}
140
+			buf.WriteString(EscapeFilter(ber.DecodeString(child.Data.Bytes())))
141
+			if child.Tag != FilterSubstringsFinal {
142
+				buf.Write(_SymbolAny)
143
+			}
144
+		}
145
+	case FilterEqualityMatch:
146
+		buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
147
+		buf.WriteByte('=')
148
+		buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
149
+	case FilterGreaterOrEqual:
150
+		buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
151
+		buf.WriteString(">=")
152
+		buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
153
+	case FilterLessOrEqual:
154
+		buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
155
+		buf.WriteString("<=")
156
+		buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
157
+	case FilterPresent:
158
+		buf.WriteString(ber.DecodeString(packet.Data.Bytes()))
159
+		buf.WriteString("=*")
160
+	case FilterApproxMatch:
161
+		buf.WriteString(ber.DecodeString(packet.Children[0].Data.Bytes()))
162
+		buf.WriteString("~=")
163
+		buf.WriteString(EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())))
164
+	case FilterExtensibleMatch:
165
+		attr := ""
166
+		dnAttributes := false
167
+		matchingRule := ""
168
+		value := ""
169
+
170
+		for _, child := range packet.Children {
171
+			switch child.Tag {
172
+			case MatchingRuleAssertionMatchingRule:
173
+				matchingRule = ber.DecodeString(child.Data.Bytes())
174
+			case MatchingRuleAssertionType:
175
+				attr = ber.DecodeString(child.Data.Bytes())
176
+			case MatchingRuleAssertionMatchValue:
177
+				value = ber.DecodeString(child.Data.Bytes())
178
+			case MatchingRuleAssertionDNAttributes:
179
+				dnAttributes = child.Value.(bool)
180
+			}
181
+		}
182
+
183
+		if len(attr) > 0 {
184
+			buf.WriteString(attr)
185
+		}
186
+		if dnAttributes {
187
+			buf.WriteString(":dn")
188
+		}
189
+		if len(matchingRule) > 0 {
190
+			buf.WriteString(":")
191
+			buf.WriteString(matchingRule)
192
+		}
193
+		buf.WriteString(":=")
194
+		buf.WriteString(EscapeFilter(value))
195
+	}
196
+
197
+	buf.WriteByte(')')
198
+
199
+	return buf.String(), nil
200
+}
201
+
202
+func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) {
203
+	for pos < len(filter) && filter[pos] == '(' {
204
+		child, newPos, err := compileFilter(filter, pos+1)
205
+		if err != nil {
206
+			return pos, err
207
+		}
208
+		pos = newPos
209
+		parent.AppendChild(child)
210
+	}
211
+	if pos == len(filter) {
212
+		return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
213
+	}
214
+
215
+	return pos + 1, nil
216
+}
217
+
218
+func compileFilter(filter string, pos int) (*ber.Packet, int, error) {
219
+	var (
220
+		packet *ber.Packet
221
+		err    error
222
+	)
223
+
224
+	defer func() {
225
+		if r := recover(); r != nil {
226
+			err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter"))
227
+		}
228
+	}()
229
+	newPos := pos
230
+
231
+	currentRune, currentWidth := utf8.DecodeRuneInString(filter[newPos:])
232
+
233
+	switch currentRune {
234
+	case utf8.RuneError:
235
+		return nil, 0, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos))
236
+	case '(':
237
+		packet, newPos, err = compileFilter(filter, pos+currentWidth)
238
+		newPos++
239
+		return packet, newPos, err
240
+	case '&':
241
+		packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd])
242
+		newPos, err = compileFilterSet(filter, pos+currentWidth, packet)
243
+		return packet, newPos, err
244
+	case '|':
245
+		packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr])
246
+		newPos, err = compileFilterSet(filter, pos+currentWidth, packet)
247
+		return packet, newPos, err
248
+	case '!':
249
+		packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot])
250
+		var child *ber.Packet
251
+		child, newPos, err = compileFilter(filter, pos+currentWidth)
252
+		packet.AppendChild(child)
253
+		return packet, newPos, err
254
+	default:
255
+		const (
256
+			stateReadingAttr                   = 0
257
+			stateReadingExtensibleMatchingRule = 1
258
+			stateReadingCondition              = 2
259
+		)
260
+
261
+		state := stateReadingAttr
262
+		attribute := bytes.NewBuffer(nil)
263
+		extensibleDNAttributes := false
264
+		extensibleMatchingRule := bytes.NewBuffer(nil)
265
+		condition := bytes.NewBuffer(nil)
266
+
267
+		for newPos < len(filter) {
268
+			remainingFilter := filter[newPos:]
269
+			currentRune, currentWidth = utf8.DecodeRuneInString(remainingFilter)
270
+			if currentRune == ')' {
271
+				break
272
+			}
273
+			if currentRune == utf8.RuneError {
274
+				return packet, newPos, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos))
275
+			}
276
+
277
+			switch state {
278
+			case stateReadingAttr:
279
+				switch {
280
+				// Extensible rule, with only DN-matching
281
+				case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:="):
282
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
283
+					extensibleDNAttributes = true
284
+					state = stateReadingCondition
285
+					newPos += 5
286
+
287
+				// Extensible rule, with DN-matching and a matching OID
288
+				case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:"):
289
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
290
+					extensibleDNAttributes = true
291
+					state = stateReadingExtensibleMatchingRule
292
+					newPos += 4
293
+
294
+				// Extensible rule, with attr only
295
+				case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="):
296
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
297
+					state = stateReadingCondition
298
+					newPos += 2
299
+
300
+				// Extensible rule, with no DN attribute matching
301
+				case currentRune == ':':
302
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
303
+					state = stateReadingExtensibleMatchingRule
304
+					newPos++
305
+
306
+				// Equality condition
307
+				case currentRune == '=':
308
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch])
309
+					state = stateReadingCondition
310
+					newPos++
311
+
312
+				// Greater-than or equal
313
+				case currentRune == '>' && strings.HasPrefix(remainingFilter, ">="):
314
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual])
315
+					state = stateReadingCondition
316
+					newPos += 2
317
+
318
+				// Less-than or equal
319
+				case currentRune == '<' && strings.HasPrefix(remainingFilter, "<="):
320
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual])
321
+					state = stateReadingCondition
322
+					newPos += 2
323
+
324
+				// Approx
325
+				case currentRune == '~' && strings.HasPrefix(remainingFilter, "~="):
326
+					packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterApproxMatch])
327
+					state = stateReadingCondition
328
+					newPos += 2
329
+
330
+				// Still reading the attribute name
331
+				default:
332
+					attribute.WriteRune(currentRune)
333
+					newPos += currentWidth
334
+				}
335
+
336
+			case stateReadingExtensibleMatchingRule:
337
+				switch {
338
+
339
+				// Matching rule OID is done
340
+				case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="):
341
+					state = stateReadingCondition
342
+					newPos += 2
343
+
344
+				// Still reading the matching rule oid
345
+				default:
346
+					extensibleMatchingRule.WriteRune(currentRune)
347
+					newPos += currentWidth
348
+				}
349
+
350
+			case stateReadingCondition:
351
+				// append to the condition
352
+				condition.WriteRune(currentRune)
353
+				newPos += currentWidth
354
+			}
355
+		}
356
+
357
+		if newPos == len(filter) {
358
+			err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter"))
359
+			return packet, newPos, err
360
+		}
361
+		if packet == nil {
362
+			err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter"))
363
+			return packet, newPos, err
364
+		}
365
+
366
+		switch {
367
+		case packet.Tag == FilterExtensibleMatch:
368
+			// MatchingRuleAssertion ::= SEQUENCE {
369
+			//         matchingRule    [1] MatchingRuleID OPTIONAL,
370
+			//         type            [2] AttributeDescription OPTIONAL,
371
+			//         matchValue      [3] AssertionValue,
372
+			//         dnAttributes    [4] BOOLEAN DEFAULT FALSE
373
+			// }
374
+
375
+			// Include the matching rule oid, if specified
376
+			if extensibleMatchingRule.Len() > 0 {
377
+				packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule.String(), MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule]))
378
+			}
379
+
380
+			// Include the attribute, if specified
381
+			if attribute.Len() > 0 {
382
+				packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute.String(), MatchingRuleAssertionMap[MatchingRuleAssertionType]))
383
+			}
384
+
385
+			// Add the value (only required child)
386
+			encodedString, encodeErr := decodeEscapedSymbols(condition.Bytes())
387
+			if encodeErr != nil {
388
+				return packet, newPos, encodeErr
389
+			}
390
+			packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchValue, encodedString, MatchingRuleAssertionMap[MatchingRuleAssertionMatchValue]))
391
+
392
+			// Defaults to false, so only include in the sequence if true
393
+			if extensibleDNAttributes {
394
+				packet.AppendChild(ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionDNAttributes, extensibleDNAttributes, MatchingRuleAssertionMap[MatchingRuleAssertionDNAttributes]))
395
+			}
396
+
397
+		case packet.Tag == FilterEqualityMatch && bytes.Equal(condition.Bytes(), _SymbolAny):
398
+			packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute.String(), FilterMap[FilterPresent])
399
+		case packet.Tag == FilterEqualityMatch && bytes.Index(condition.Bytes(), _SymbolAny) > -1:
400
+			packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute.String(), "Attribute"))
401
+			packet.Tag = FilterSubstrings
402
+			packet.Description = FilterMap[uint64(packet.Tag)]
403
+			seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings")
404
+			parts := bytes.Split(condition.Bytes(), _SymbolAny)
405
+			for i, part := range parts {
406
+				if len(part) == 0 {
407
+					continue
408
+				}
409
+				var tag ber.Tag
410
+				switch i {
411
+				case 0:
412
+					tag = FilterSubstringsInitial
413
+				case len(parts) - 1:
414
+					tag = FilterSubstringsFinal
415
+				default:
416
+					tag = FilterSubstringsAny
417
+				}
418
+				encodedString, encodeErr := decodeEscapedSymbols(part)
419
+				if encodeErr != nil {
420
+					return packet, newPos, encodeErr
421
+				}
422
+				seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, tag, encodedString, FilterSubstringsMap[uint64(tag)]))
423
+			}
424
+			packet.AppendChild(seq)
425
+		default:
426
+			encodedString, encodeErr := decodeEscapedSymbols(condition.Bytes())
427
+			if encodeErr != nil {
428
+				return packet, newPos, encodeErr
429
+			}
430
+			packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute.String(), "Attribute"))
431
+			packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, encodedString, "Condition"))
432
+		}
433
+
434
+		newPos += currentWidth
435
+		return packet, newPos, err
436
+	}
437
+}
438
+
439
+// Convert from "ABC\xx\xx\xx" form to literal bytes for transport
440
+func decodeEscapedSymbols(src []byte) (string, error) {
441
+
442
+	var (
443
+		buffer  bytes.Buffer
444
+		offset  int
445
+		reader  = bytes.NewReader(src)
446
+		byteHex []byte
447
+		byteVal []byte
448
+	)
449
+
450
+	for {
451
+		runeVal, runeSize, err := reader.ReadRune()
452
+		if err == io.EOF {
453
+			return buffer.String(), nil
454
+		} else if err != nil {
455
+			return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: failed to read filter: %v", err))
456
+		} else if runeVal == unicode.ReplacementChar {
457
+			return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", offset))
458
+		}
459
+
460
+		if runeVal == '\\' {
461
+			// http://tools.ietf.org/search/rfc4515
462
+			// \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not
463
+			// being a member of UTF1SUBSET.
464
+			if byteHex == nil {
465
+				byteHex = make([]byte, 2)
466
+				byteVal = make([]byte, 1)
467
+			}
468
+
469
+			if _, err := io.ReadFull(reader, byteHex); err != nil {
470
+				if err == io.ErrUnexpectedEOF {
471
+					return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter"))
472
+				}
473
+				return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: invalid characters for escape in filter: %v", err))
474
+			}
475
+
476
+			if _, err := hexpac.Decode(byteVal, byteHex); err != nil {
477
+				return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: invalid characters for escape in filter: %v", err))
478
+			}
479
+
480
+			buffer.Write(byteVal)
481
+		} else {
482
+			buffer.WriteRune(runeVal)
483
+		}
484
+
485
+		offset += runeSize
486
+	}
487
+}

+ 5
- 0
vendor/github.com/go-ldap/ldap/v3/go.mod View File

@@ -0,0 +1,5 @@
1
+module github.com/go-ldap/ldap/v3
2
+
3
+go 1.13
4
+
5
+require github.com/go-asn1-ber/asn1-ber v1.3.1

+ 2
- 0
vendor/github.com/go-ldap/ldap/v3/go.sum View File

@@ -0,0 +1,2 @@
1
+github.com/go-asn1-ber/asn1-ber v1.3.1 h1:gvPdv/Hr++TRFCl0UbPFHC54P9N9jgsRPnmnr419Uck=
2
+github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=

+ 340
- 0
vendor/github.com/go-ldap/ldap/v3/ldap.go View File

@@ -0,0 +1,340 @@
1
+package ldap
2
+
3
+import (
4
+	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+
8
+	ber "github.com/go-asn1-ber/asn1-ber"
9
+)
10
+
11
+// LDAP Application Codes
12
+const (
13
+	ApplicationBindRequest           = 0
14
+	ApplicationBindResponse          = 1
15
+	ApplicationUnbindRequest         = 2
16
+	ApplicationSearchRequest         = 3
17
+	ApplicationSearchResultEntry     = 4
18
+	ApplicationSearchResultDone      = 5
19
+	ApplicationModifyRequest         = 6
20
+	ApplicationModifyResponse        = 7
21
+	ApplicationAddRequest            = 8
22
+	ApplicationAddResponse           = 9
23
+	ApplicationDelRequest            = 10
24
+	ApplicationDelResponse           = 11
25
+	ApplicationModifyDNRequest       = 12
26
+	ApplicationModifyDNResponse      = 13
27
+	ApplicationCompareRequest        = 14
28
+	ApplicationCompareResponse       = 15
29
+	ApplicationAbandonRequest        = 16
30
+	ApplicationSearchResultReference = 19
31
+	ApplicationExtendedRequest       = 23
32
+	ApplicationExtendedResponse      = 24
33
+)
34
+
35
+// ApplicationMap contains human readable descriptions of LDAP Application Codes
36
+var ApplicationMap = map[uint8]string{
37
+	ApplicationBindRequest:           "Bind Request",
38
+	ApplicationBindResponse:          "Bind Response",
39
+	ApplicationUnbindRequest:         "Unbind Request",
40
+	ApplicationSearchRequest:         "Search Request",
41
+	ApplicationSearchResultEntry:     "Search Result Entry",
42
+	ApplicationSearchResultDone:      "Search Result Done",
43
+	ApplicationModifyRequest:         "Modify Request",
44
+	ApplicationModifyResponse:        "Modify Response",
45
+	ApplicationAddRequest:            "Add Request",
46
+	ApplicationAddResponse:           "Add Response",
47
+	ApplicationDelRequest:            "Del Request",
48
+	ApplicationDelResponse:           "Del Response",
49
+	ApplicationModifyDNRequest:       "Modify DN Request",
50
+	ApplicationModifyDNResponse:      "Modify DN Response",
51
+	ApplicationCompareRequest:        "Compare Request",
52
+	ApplicationCompareResponse:       "Compare Response",
53
+	ApplicationAbandonRequest:        "Abandon Request",
54
+	ApplicationSearchResultReference: "Search Result Reference",
55
+	ApplicationExtendedRequest:       "Extended Request",
56
+	ApplicationExtendedResponse:      "Extended Response",
57
+}
58
+
59
+// Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10)
60
+const (
61
+	BeheraPasswordExpired             = 0
62
+	BeheraAccountLocked               = 1
63
+	BeheraChangeAfterReset            = 2
64
+	BeheraPasswordModNotAllowed       = 3
65
+	BeheraMustSupplyOldPassword       = 4
66
+	BeheraInsufficientPasswordQuality = 5
67
+	BeheraPasswordTooShort            = 6
68
+	BeheraPasswordTooYoung            = 7
69
+	BeheraPasswordInHistory           = 8
70
+)
71
+
72
+// BeheraPasswordPolicyErrorMap contains human readable descriptions of Behera Password Policy error codes
73
+var BeheraPasswordPolicyErrorMap = map[int8]string{
74
+	BeheraPasswordExpired:             "Password expired",
75
+	BeheraAccountLocked:               "Account locked",
76
+	BeheraChangeAfterReset:            "Password must be changed",
77
+	BeheraPasswordModNotAllowed:       "Policy prevents password modification",
78
+	BeheraMustSupplyOldPassword:       "Policy requires old password in order to change password",
79
+	BeheraInsufficientPasswordQuality: "Password fails quality checks",
80
+	BeheraPasswordTooShort:            "Password is too short for policy",
81
+	BeheraPasswordTooYoung:            "Password has been changed too recently",
82
+	BeheraPasswordInHistory:           "New password is in list of old passwords",
83
+}
84
+
85
+// Adds descriptions to an LDAP Response packet for debugging
86
+func addLDAPDescriptions(packet *ber.Packet) (err error) {
87
+	defer func() {
88
+		if r := recover(); r != nil {
89
+			err = NewError(ErrorDebugging, fmt.Errorf("ldap: cannot process packet to add descriptions: %s", r))
90
+		}
91
+	}()
92
+	packet.Description = "LDAP Response"
93
+	packet.Children[0].Description = "Message ID"
94
+
95
+	application := uint8(packet.Children[1].Tag)
96
+	packet.Children[1].Description = ApplicationMap[application]
97
+
98
+	switch application {
99
+	case ApplicationBindRequest:
100
+		err = addRequestDescriptions(packet)
101
+	case ApplicationBindResponse:
102
+		err = addDefaultLDAPResponseDescriptions(packet)
103
+	case ApplicationUnbindRequest:
104
+		err = addRequestDescriptions(packet)
105
+	case ApplicationSearchRequest:
106
+		err = addRequestDescriptions(packet)
107
+	case ApplicationSearchResultEntry:
108
+		packet.Children[1].Children[0].Description = "Object Name"
109
+		packet.Children[1].Children[1].Description = "Attributes"
110
+		for _, child := range packet.Children[1].Children[1].Children {
111
+			child.Description = "Attribute"
112
+			child.Children[0].Description = "Attribute Name"
113
+			child.Children[1].Description = "Attribute Values"
114
+			for _, grandchild := range child.Children[1].Children {
115
+				grandchild.Description = "Attribute Value"
116
+			}
117
+		}
118
+		if len(packet.Children) == 3 {
119
+			err = addControlDescriptions(packet.Children[2])
120
+		}
121
+	case ApplicationSearchResultDone:
122
+		err = addDefaultLDAPResponseDescriptions(packet)
123
+	case ApplicationModifyRequest:
124
+		err = addRequestDescriptions(packet)
125
+	case ApplicationModifyResponse:
126
+	case ApplicationAddRequest:
127
+		err = addRequestDescriptions(packet)
128
+	case ApplicationAddResponse:
129
+	case ApplicationDelRequest:
130
+		err = addRequestDescriptions(packet)
131
+	case ApplicationDelResponse:
132
+	case ApplicationModifyDNRequest:
133
+		err = addRequestDescriptions(packet)
134
+	case ApplicationModifyDNResponse:
135
+	case ApplicationCompareRequest:
136
+		err = addRequestDescriptions(packet)
137
+	case ApplicationCompareResponse:
138
+	case ApplicationAbandonRequest:
139
+		err = addRequestDescriptions(packet)
140
+	case ApplicationSearchResultReference:
141
+	case ApplicationExtendedRequest:
142
+		err = addRequestDescriptions(packet)
143
+	case ApplicationExtendedResponse:
144
+	}
145
+
146
+	return err
147
+}
148
+
149
+func addControlDescriptions(packet *ber.Packet) error {
150
+	packet.Description = "Controls"
151
+	for _, child := range packet.Children {
152
+		var value *ber.Packet
153
+		controlType := ""
154
+		child.Description = "Control"
155
+		switch len(child.Children) {
156
+		case 0:
157
+			// at least one child is required for control type
158
+			return fmt.Errorf("at least one child is required for control type")
159
+
160
+		case 1:
161
+			// just type, no criticality or value
162
+			controlType = child.Children[0].Value.(string)
163
+			child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
164
+
165
+		case 2:
166
+			controlType = child.Children[0].Value.(string)
167
+			child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
168
+			// Children[1] could be criticality or value (both are optional)
169
+			// duck-type on whether this is a boolean
170
+			if _, ok := child.Children[1].Value.(bool); ok {
171
+				child.Children[1].Description = "Criticality"
172
+			} else {
173
+				child.Children[1].Description = "Control Value"
174
+				value = child.Children[1]
175
+			}
176
+
177
+		case 3:
178
+			// criticality and value present
179
+			controlType = child.Children[0].Value.(string)
180
+			child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
181
+			child.Children[1].Description = "Criticality"
182
+			child.Children[2].Description = "Control Value"
183
+			value = child.Children[2]
184
+
185
+		default:
186
+			// more than 3 children is invalid
187
+			return fmt.Errorf("more than 3 children for control packet found")
188
+		}
189
+
190
+		if value == nil {
191
+			continue
192
+		}
193
+		switch controlType {
194
+		case ControlTypePaging:
195
+			value.Description += " (Paging)"
196
+			if value.Value != nil {
197
+				valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
198
+				if err != nil {
199
+					return fmt.Errorf("failed to decode data bytes: %s", err)
200
+				}
201
+				value.Data.Truncate(0)
202
+				value.Value = nil
203
+				valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
204
+				value.AppendChild(valueChildren)
205
+			}
206
+			value.Children[0].Description = "Real Search Control Value"
207
+			value.Children[0].Children[0].Description = "Paging Size"
208
+			value.Children[0].Children[1].Description = "Cookie"
209
+
210
+		case ControlTypeBeheraPasswordPolicy:
211
+			value.Description += " (Password Policy - Behera Draft)"
212
+			if value.Value != nil {
213
+				valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
214
+				if err != nil {
215
+					return fmt.Errorf("failed to decode data bytes: %s", err)
216
+				}
217
+				value.Data.Truncate(0)
218
+				value.Value = nil
219
+				value.AppendChild(valueChildren)
220
+			}
221
+			sequence := value.Children[0]
222
+			for _, child := range sequence.Children {
223
+				if child.Tag == 0 {
224
+					//Warning
225
+					warningPacket := child.Children[0]
226
+					packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
227
+					if err != nil {
228
+						return fmt.Errorf("failed to decode data bytes: %s", err)
229
+					}
230
+					val, ok := packet.Value.(int64)
231
+					if ok {
232
+						if warningPacket.Tag == 0 {
233
+							//timeBeforeExpiration
234
+							value.Description += " (TimeBeforeExpiration)"
235
+							warningPacket.Value = val
236
+						} else if warningPacket.Tag == 1 {
237
+							//graceAuthNsRemaining
238
+							value.Description += " (GraceAuthNsRemaining)"
239
+							warningPacket.Value = val
240
+						}
241
+					}
242
+				} else if child.Tag == 1 {
243
+					// Error
244
+					packet, err := ber.DecodePacketErr(child.Data.Bytes())
245
+					if err != nil {
246
+						return fmt.Errorf("failed to decode data bytes: %s", err)
247
+					}
248
+					val, ok := packet.Value.(int8)
249
+					if !ok {
250
+						val = -1
251
+					}
252
+					child.Description = "Error"
253
+					child.Value = val
254
+				}
255
+			}
256
+		}
257
+	}
258
+	return nil
259
+}
260
+
261
+func addRequestDescriptions(packet *ber.Packet) error {
262
+	packet.Description = "LDAP Request"
263
+	packet.Children[0].Description = "Message ID"
264
+	packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
265
+	if len(packet.Children) == 3 {
266
+		return addControlDescriptions(packet.Children[2])
267
+	}
268
+	return nil
269
+}
270
+
271
+func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error {
272
+	err := GetLDAPError(packet)
273
+	if err == nil {
274
+		return nil
275
+	}
276
+	packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[err.(*Error).ResultCode] + ")"
277
+	packet.Children[1].Children[1].Description = "Matched DN (" + err.(*Error).MatchedDN + ")"
278
+	packet.Children[1].Children[2].Description = "Error Message"
279
+	if len(packet.Children[1].Children) > 3 {
280
+		packet.Children[1].Children[3].Description = "Referral"
281
+	}
282
+	if len(packet.Children) == 3 {
283
+		return addControlDescriptions(packet.Children[2])
284
+	}
285
+	return nil
286
+}
287
+
288
+// DebugBinaryFile reads and prints packets from the given filename
289
+func DebugBinaryFile(fileName string) error {
290
+	file, err := ioutil.ReadFile(fileName)
291
+	if err != nil {
292
+		return NewError(ErrorDebugging, err)
293
+	}
294
+	ber.PrintBytes(os.Stdout, file, "")
295
+	packet, err := ber.DecodePacketErr(file)
296
+	if err != nil {
297
+		return fmt.Errorf("failed to decode packet: %s", err)
298
+	}
299
+	if err := addLDAPDescriptions(packet); err != nil {
300
+		return err
301
+	}
302
+	ber.PrintPacket(packet)
303
+
304
+	return nil
305
+}
306
+
307
+var hex = "0123456789abcdef"
308
+
309
+func mustEscape(c byte) bool {
310
+	return c > 0x7f || c == '(' || c == ')' || c == '\\' || c == '*' || c == 0
311
+}
312
+
313
+// EscapeFilter escapes from the provided LDAP filter string the special
314
+// characters in the set `()*\` and those out of the range 0 < c < 0x80,
315
+// as defined in RFC4515.
316
+func EscapeFilter(filter string) string {
317
+	escape := 0
318
+	for i := 0; i < len(filter); i++ {
319
+		if mustEscape(filter[i]) {
320
+			escape++
321
+		}
322
+	}
323
+	if escape == 0 {
324
+		return filter
325
+	}
326
+	buf := make([]byte, len(filter)+escape*2)
327
+	for i, j := 0, 0; i < len(filter); i++ {
328
+		c := filter[i]
329
+		if mustEscape(c) {
330
+			buf[j+0] = '\\'
331
+			buf[j+1] = hex[c>>4]
332
+			buf[j+2] = hex[c&0xf]
333
+			j += 3
334
+		} else {
335
+			buf[j] = c
336
+			j++
337
+		}
338
+	}
339
+	return string(buf)
340
+}

+ 75
- 0
vendor/github.com/go-ldap/ldap/v3/moddn.go View File

@@ -0,0 +1,75 @@
1
+package ldap
2
+
3
+import (
4
+	"log"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// ModifyDNRequest holds the request to modify a DN
10
+type ModifyDNRequest struct {
11
+	DN           string
12
+	NewRDN       string
13
+	DeleteOldRDN bool
14
+	NewSuperior  string
15
+}
16
+
17
+// NewModifyDNRequest creates a new request which can be passed to ModifyDN().
18
+//
19
+// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an
20
+// empty string for just changing the object's RDN.
21
+//
22
+// For moving the object without renaming, the "rdn" must be the first
23
+// RDN of the given DN.
24
+//
25
+// A call like
26
+//   mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
27
+// will setup the request to just rename uid=someone,dc=example,dc=org to
28
+// uid=newname,dc=example,dc=org.
29
+func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest {
30
+	return &ModifyDNRequest{
31
+		DN:           dn,
32
+		NewRDN:       rdn,
33
+		DeleteOldRDN: delOld,
34
+		NewSuperior:  newSup,
35
+	}
36
+}
37
+
38
+func (req *ModifyDNRequest) appendTo(envelope *ber.Packet) error {
39
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request")
40
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
41
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.NewRDN, "New RDN"))
42
+	pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.DeleteOldRDN, "Delete old RDN"))
43
+	if req.NewSuperior != "" {
44
+		pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.NewSuperior, "New Superior"))
45
+	}
46
+
47
+	envelope.AppendChild(pkt)
48
+
49
+	return nil
50
+}
51
+
52
+// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument
53
+// to NewModifyDNRequest() is not "").
54
+func (l *Conn) ModifyDN(m *ModifyDNRequest) error {
55
+	msgCtx, err := l.doRequest(m)
56
+	if err != nil {
57
+		return err
58
+	}
59
+	defer l.finishMessage(msgCtx)
60
+
61
+	packet, err := l.readPacket(msgCtx)
62
+	if err != nil {
63
+		return err
64
+	}
65
+
66
+	if packet.Children[1].Tag == ApplicationModifyDNResponse {
67
+		err := GetLDAPError(packet)
68
+		if err != nil {
69
+			return err
70
+		}
71
+	} else {
72
+		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
73
+	}
74
+	return nil
75
+}

+ 132
- 0
vendor/github.com/go-ldap/ldap/v3/modify.go View File

@@ -0,0 +1,132 @@
1
+package ldap
2
+
3
+import (
4
+	"log"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+// Change operation choices
10
+const (
11
+	AddAttribute       = 0
12
+	DeleteAttribute    = 1
13
+	ReplaceAttribute   = 2
14
+	IncrementAttribute = 3 // (https://tools.ietf.org/html/rfc4525)
15
+)
16
+
17
+// PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
18
+type PartialAttribute struct {
19
+	// Type is the type of the partial attribute
20
+	Type string
21
+	// Vals are the values of the partial attribute
22
+	Vals []string
23
+}
24
+
25
+func (p *PartialAttribute) encode() *ber.Packet {
26
+	seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
27
+	seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.Type, "Type"))
28
+	set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue")
29
+	for _, value := range p.Vals {
30
+		set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals"))
31
+	}
32
+	seq.AppendChild(set)
33
+	return seq
34
+}
35
+
36
+// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
37
+type Change struct {
38
+	// Operation is the type of change to be made
39
+	Operation uint
40
+	// Modification is the attribute to be modified
41
+	Modification PartialAttribute
42
+}
43
+
44
+func (c *Change) encode() *ber.Packet {
45
+	change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
46
+	change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
47
+	change.AppendChild(c.Modification.encode())
48
+	return change
49
+}
50
+
51
+// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
52
+type ModifyRequest struct {
53
+	// DN is the distinguishedName of the directory entry to modify
54
+	DN string
55
+	// Changes contain the attributes to modify
56
+	Changes []Change
57
+	// Controls hold optional controls to send with the request
58
+	Controls []Control
59
+}
60
+
61
+// Add appends the given attribute to the list of changes to be made
62
+func (req *ModifyRequest) Add(attrType string, attrVals []string) {
63
+	req.appendChange(AddAttribute, attrType, attrVals)
64
+}
65
+
66
+// Delete appends the given attribute to the list of changes to be made
67
+func (req *ModifyRequest) Delete(attrType string, attrVals []string) {
68
+	req.appendChange(DeleteAttribute, attrType, attrVals)
69
+}
70
+
71
+// Replace appends the given attribute to the list of changes to be made
72
+func (req *ModifyRequest) Replace(attrType string, attrVals []string) {
73
+	req.appendChange(ReplaceAttribute, attrType, attrVals)
74
+}
75
+
76
+// Increment appends the given attribute to the list of changes to be made
77
+func (req *ModifyRequest) Increment(attrType string, attrVal string) {
78
+	req.appendChange(IncrementAttribute, attrType, []string{attrVal})
79
+}
80
+
81
+func (req *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
82
+	req.Changes = append(req.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
83
+}
84
+
85
+func (req *ModifyRequest) appendTo(envelope *ber.Packet) error {
86
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
87
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
88
+	changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
89
+	for _, change := range req.Changes {
90
+		changes.AppendChild(change.encode())
91
+	}
92
+	pkt.AppendChild(changes)
93
+
94
+	envelope.AppendChild(pkt)
95
+	if len(req.Controls) > 0 {
96
+		envelope.AppendChild(encodeControls(req.Controls))
97
+	}
98
+
99
+	return nil
100
+}
101
+
102
+// NewModifyRequest creates a modify request for the given DN
103
+func NewModifyRequest(dn string, controls []Control) *ModifyRequest {
104
+	return &ModifyRequest{
105
+		DN:       dn,
106
+		Controls: controls,
107
+	}
108
+}
109
+
110
+// Modify performs the ModifyRequest
111
+func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
112
+	msgCtx, err := l.doRequest(modifyRequest)
113
+	if err != nil {
114
+		return err
115
+	}
116
+	defer l.finishMessage(msgCtx)
117
+
118
+	packet, err := l.readPacket(msgCtx)
119
+	if err != nil {
120
+		return err
121
+	}
122
+
123
+	if packet.Children[1].Tag == ApplicationModifyResponse {
124
+		err := GetLDAPError(packet)
125
+		if err != nil {
126
+			return err
127
+		}
128
+	} else {
129
+		log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
130
+	}
131
+	return nil
132
+}

+ 126
- 0
vendor/github.com/go-ldap/ldap/v3/passwdmodify.go View File

@@ -0,0 +1,126 @@
1
+package ldap
2
+
3
+import (
4
+	"fmt"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+const (
10
+	passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1"
11
+)
12
+
13
+// PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt
14
+type PasswordModifyRequest struct {
15
+	// UserIdentity is an optional string representation of the user associated with the request.
16
+	// This string may or may not be an LDAPDN [RFC2253].
17
+	// If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session
18
+	UserIdentity string
19
+	// OldPassword, if present, contains the user's current password
20
+	OldPassword string
21
+	// NewPassword, if present, contains the desired password for this user
22
+	NewPassword string
23
+}
24
+
25
+// PasswordModifyResult holds the server response to a PasswordModifyRequest
26
+type PasswordModifyResult struct {
27
+	// GeneratedPassword holds a password generated by the server, if present
28
+	GeneratedPassword string
29
+	// Referral are the returned referral
30
+	Referral string
31
+}
32
+
33
+func (req *PasswordModifyRequest) appendTo(envelope *ber.Packet) error {
34
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation")
35
+	pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID"))
36
+
37
+	extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request")
38
+	passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request")
39
+	if req.UserIdentity != "" {
40
+		passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.UserIdentity, "User Identity"))
41
+	}
42
+	if req.OldPassword != "" {
43
+		passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, req.OldPassword, "Old Password"))
44
+	}
45
+	if req.NewPassword != "" {
46
+		passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, req.NewPassword, "New Password"))
47
+	}
48
+	extendedRequestValue.AppendChild(passwordModifyRequestValue)
49
+
50
+	pkt.AppendChild(extendedRequestValue)
51
+
52
+	envelope.AppendChild(pkt)
53
+
54
+	return nil
55
+}
56
+
57
+// NewPasswordModifyRequest creates a new PasswordModifyRequest
58
+//
59
+// According to the RFC 3602 (https://tools.ietf.org/html/rfc3062):
60
+// userIdentity is a string representing the user associated with the request.
61
+// This string may or may not be an LDAPDN (RFC 2253).
62
+// If userIdentity is empty then the operation will act on the user associated
63
+// with the session.
64
+//
65
+// oldPassword is the current user's password, it can be empty or it can be
66
+// needed depending on the session user access rights (usually an administrator
67
+// can change a user's password without knowing the current one) and the
68
+// password policy (see pwdSafeModify password policy's attribute)
69
+//
70
+// newPassword is the desired user's password. If empty the server can return
71
+// an error or generate a new password that will be available in the
72
+// PasswordModifyResult.GeneratedPassword
73
+//
74
+func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {
75
+	return &PasswordModifyRequest{
76
+		UserIdentity: userIdentity,
77
+		OldPassword:  oldPassword,
78
+		NewPassword:  newPassword,
79
+	}
80
+}
81
+
82
+// PasswordModify performs the modification request
83
+func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) {
84
+	msgCtx, err := l.doRequest(passwordModifyRequest)
85
+	if err != nil {
86
+		return nil, err
87
+	}
88
+	defer l.finishMessage(msgCtx)
89
+
90
+	packet, err := l.readPacket(msgCtx)
91
+	if err != nil {
92
+		return nil, err
93
+	}
94
+
95
+	result := &PasswordModifyResult{}
96
+
97
+	if packet.Children[1].Tag == ApplicationExtendedResponse {
98
+		err := GetLDAPError(packet)
99
+		if err != nil {
100
+			if IsErrorWithCode(err, LDAPResultReferral) {
101
+				for _, child := range packet.Children[1].Children {
102
+					if child.Tag == 3 {
103
+						result.Referral = child.Children[0].Value.(string)
104
+					}
105
+				}
106
+			}
107
+			return result, err
108
+		}
109
+	} else {
110
+		return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag))
111
+	}
112
+
113
+	extendedResponse := packet.Children[1]
114
+	for _, child := range extendedResponse.Children {
115
+		if child.Tag == 11 {
116
+			passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes())
117
+			if len(passwordModifyResponseValue.Children) == 1 {
118
+				if passwordModifyResponseValue.Children[0].Tag == 0 {
119
+					result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes())
120
+				}
121
+			}
122
+		}
123
+	}
124
+
125
+	return result, nil
126
+}

+ 66
- 0
vendor/github.com/go-ldap/ldap/v3/request.go View File

@@ -0,0 +1,66 @@
1
+package ldap
2
+
3
+import (
4
+	"errors"
5
+
6
+	ber "github.com/go-asn1-ber/asn1-ber"
7
+)
8
+
9
+var (
10
+	errRespChanClosed = errors.New("ldap: response channel closed")
11
+	errCouldNotRetMsg = errors.New("ldap: could not retrieve message")
12
+)
13
+
14
+type request interface {
15
+	appendTo(*ber.Packet) error
16
+}
17
+
18
+type requestFunc func(*ber.Packet) error
19
+
20
+func (f requestFunc) appendTo(p *ber.Packet) error {
21
+	return f(p)
22
+}
23
+
24
+func (l *Conn) doRequest(req request) (*messageContext, error) {
25
+	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
26
+	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
27
+	if err := req.appendTo(packet); err != nil {
28
+		return nil, err
29
+	}
30
+
31
+	if l.Debug {
32
+		l.Debug.PrintPacket(packet)
33
+	}
34
+
35
+	msgCtx, err := l.sendMessage(packet)
36
+	if err != nil {
37
+		return nil, err
38
+	}
39
+	l.Debug.Printf("%d: returning", msgCtx.id)
40
+	return msgCtx, nil
41
+}
42
+
43
+func (l *Conn) readPacket(msgCtx *messageContext) (*ber.Packet, error) {
44
+	l.Debug.Printf("%d: waiting for response", msgCtx.id)
45
+	packetResponse, ok := <-msgCtx.responses
46
+	if !ok {
47
+		return nil, NewError(ErrorNetwork, errRespChanClosed)
48
+	}
49
+	packet, err := packetResponse.ReadPacket()
50
+	l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
51
+	if err != nil {
52
+		return nil, err
53
+	}
54
+
55
+	if packet == nil {
56
+		return nil, NewError(ErrorNetwork, errCouldNotRetMsg)
57
+	}
58
+
59
+	if l.Debug {
60
+		if err = addLDAPDescriptions(packet); err != nil {
61
+			return nil, err
62
+		}
63
+		l.Debug.PrintPacket(packet)
64
+	}
65
+	return packet, nil
66
+}

+ 370
- 0
vendor/github.com/go-ldap/ldap/v3/search.go View File

@@ -0,0 +1,370 @@
1
+package ldap
2
+
3
+import (
4
+	"errors"
5
+	"fmt"
6
+	"sort"
7
+	"strings"
8
+
9
+	ber "github.com/go-asn1-ber/asn1-ber"
10
+)
11
+
12
+// scope choices
13
+const (
14
+	ScopeBaseObject   = 0
15
+	ScopeSingleLevel  = 1
16
+	ScopeWholeSubtree = 2
17
+)
18
+
19
+// ScopeMap contains human readable descriptions of scope choices
20
+var ScopeMap = map[int]string{
21
+	ScopeBaseObject:   "Base Object",
22
+	ScopeSingleLevel:  "Single Level",
23
+	ScopeWholeSubtree: "Whole Subtree",
24
+}
25
+
26
+// derefAliases
27
+const (
28
+	NeverDerefAliases   = 0
29
+	DerefInSearching    = 1
30
+	DerefFindingBaseObj = 2
31
+	DerefAlways         = 3
32
+)
33
+
34
+// DerefMap contains human readable descriptions of derefAliases choices
35
+var DerefMap = map[int]string{
36
+	NeverDerefAliases:   "NeverDerefAliases",
37
+	DerefInSearching:    "DerefInSearching",
38
+	DerefFindingBaseObj: "DerefFindingBaseObj",
39
+	DerefAlways:         "DerefAlways",
40
+}
41
+
42
+// NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs.
43
+// The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the
44
+// same input map of attributes, the output entry will contain the same order of attributes
45
+func NewEntry(dn string, attributes map[string][]string) *Entry {
46
+	var attributeNames []string
47
+	for attributeName := range attributes {
48
+		attributeNames = append(attributeNames, attributeName)
49
+	}
50
+	sort.Strings(attributeNames)
51
+
52
+	var encodedAttributes []*EntryAttribute
53
+	for _, attributeName := range attributeNames {
54
+		encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName]))
55
+	}
56
+	return &Entry{
57
+		DN:         dn,
58
+		Attributes: encodedAttributes,
59
+	}
60
+}
61
+
62
+// Entry represents a single search result entry
63
+type Entry struct {
64
+	// DN is the distinguished name of the entry
65
+	DN string
66
+	// Attributes are the returned attributes for the entry
67
+	Attributes []*EntryAttribute
68
+}
69
+
70
+// GetAttributeValues returns the values for the named attribute, or an empty list
71
+func (e *Entry) GetAttributeValues(attribute string) []string {
72
+	for _, attr := range e.Attributes {
73
+		if attr.Name == attribute {
74
+			return attr.Values
75
+		}
76
+	}
77
+	return []string{}
78
+}
79
+
80
+// GetRawAttributeValues returns the byte values for the named attribute, or an empty list
81
+func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
82
+	for _, attr := range e.Attributes {
83
+		if attr.Name == attribute {
84
+			return attr.ByteValues
85
+		}
86
+	}
87
+	return [][]byte{}
88
+}
89
+
90
+// GetAttributeValue returns the first value for the named attribute, or ""
91
+func (e *Entry) GetAttributeValue(attribute string) string {
92
+	values := e.GetAttributeValues(attribute)
93
+	if len(values) == 0 {
94
+		return ""
95
+	}
96
+	return values[0]
97
+}
98
+
99
+// GetRawAttributeValue returns the first value for the named attribute, or an empty slice
100
+func (e *Entry) GetRawAttributeValue(attribute string) []byte {
101
+	values := e.GetRawAttributeValues(attribute)
102
+	if len(values) == 0 {
103
+		return []byte{}
104
+	}
105
+	return values[0]
106
+}
107
+
108
+// Print outputs a human-readable description
109
+func (e *Entry) Print() {
110
+	fmt.Printf("DN: %s\n", e.DN)
111
+	for _, attr := range e.Attributes {
112
+		attr.Print()
113
+	}
114
+}
115
+
116
+// PrettyPrint outputs a human-readable description indenting
117
+func (e *Entry) PrettyPrint(indent int) {
118
+	fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
119
+	for _, attr := range e.Attributes {
120
+		attr.PrettyPrint(indent + 2)
121
+	}
122
+}
123
+
124
+// NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
125
+func NewEntryAttribute(name string, values []string) *EntryAttribute {
126
+	var bytes [][]byte
127
+	for _, value := range values {
128
+		bytes = append(bytes, []byte(value))
129
+	}
130
+	return &EntryAttribute{
131
+		Name:       name,
132
+		Values:     values,
133
+		ByteValues: bytes,
134
+	}
135
+}
136
+
137
+// EntryAttribute holds a single attribute
138
+type EntryAttribute struct {
139
+	// Name is the name of the attribute
140
+	Name string
141
+	// Values contain the string values of the attribute
142
+	Values []string
143
+	// ByteValues contain the raw values of the attribute
144
+	ByteValues [][]byte
145
+}
146
+
147
+// Print outputs a human-readable description
148
+func (e *EntryAttribute) Print() {
149
+	fmt.Printf("%s: %s\n", e.Name, e.Values)
150
+}
151
+
152
+// PrettyPrint outputs a human-readable description with indenting
153
+func (e *EntryAttribute) PrettyPrint(indent int) {
154
+	fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
155
+}
156
+
157
+// SearchResult holds the server's response to a search request
158
+type SearchResult struct {
159
+	// Entries are the returned entries
160
+	Entries []*Entry
161
+	// Referrals are the returned referrals
162
+	Referrals []string
163
+	// Controls are the returned controls
164
+	Controls []Control
165
+}
166
+
167
+// Print outputs a human-readable description
168
+func (s *SearchResult) Print() {
169
+	for _, entry := range s.Entries {
170
+		entry.Print()
171
+	}
172
+}
173
+
174
+// PrettyPrint outputs a human-readable description with indenting
175
+func (s *SearchResult) PrettyPrint(indent int) {
176
+	for _, entry := range s.Entries {
177
+		entry.PrettyPrint(indent)
178
+	}
179
+}
180
+
181
+// SearchRequest represents a search request to send to the server
182
+type SearchRequest struct {
183
+	BaseDN       string
184
+	Scope        int
185
+	DerefAliases int
186
+	SizeLimit    int
187
+	TimeLimit    int
188
+	TypesOnly    bool
189
+	Filter       string
190
+	Attributes   []string
191
+	Controls     []Control
192
+}
193
+
194
+func (req *SearchRequest) appendTo(envelope *ber.Packet) error {
195
+	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
196
+	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.BaseDN, "Base DN"))
197
+	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.Scope), "Scope"))
198
+	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.DerefAliases), "Deref Aliases"))
199
+	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.SizeLimit), "Size Limit"))
200
+	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.TimeLimit), "Time Limit"))
201
+	pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.TypesOnly, "Types Only"))
202
+	// compile and encode filter
203
+	filterPacket, err := CompileFilter(req.Filter)
204
+	if err != nil {
205
+		return err
206
+	}
207
+	pkt.AppendChild(filterPacket)
208
+	// encode attributes
209
+	attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
210
+	for _, attribute := range req.Attributes {
211
+		attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
212
+	}
213
+	pkt.AppendChild(attributesPacket)
214
+
215
+	envelope.AppendChild(pkt)
216
+	if len(req.Controls) > 0 {
217
+		envelope.AppendChild(encodeControls(req.Controls))
218
+	}
219
+
220
+	return nil
221
+}
222
+
223
+// NewSearchRequest creates a new search request
224
+func NewSearchRequest(
225
+	BaseDN string,
226
+	Scope, DerefAliases, SizeLimit, TimeLimit int,
227
+	TypesOnly bool,
228
+	Filter string,
229
+	Attributes []string,
230
+	Controls []Control,
231
+) *SearchRequest {
232
+	return &SearchRequest{
233
+		BaseDN:       BaseDN,
234
+		Scope:        Scope,
235
+		DerefAliases: DerefAliases,
236
+		SizeLimit:    SizeLimit,
237
+		TimeLimit:    TimeLimit,
238
+		TypesOnly:    TypesOnly,
239
+		Filter:       Filter,
240
+		Attributes:   Attributes,
241
+		Controls:     Controls,
242
+	}
243
+}
244
+
245
+// SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the
246
+// search request. All paged LDAP query responses will be buffered and the final result will be returned atomically.
247
+// The following four cases are possible given the arguments:
248
+//  - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
249
+//  - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
250
+//  - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
251
+//  - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries
252
+// A requested pagingSize of 0 is interpreted as no limit by LDAP servers.
253
+func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
254
+	var pagingControl *ControlPaging
255
+
256
+	control := FindControl(searchRequest.Controls, ControlTypePaging)
257
+	if control == nil {
258
+		pagingControl = NewControlPaging(pagingSize)
259
+		searchRequest.Controls = append(searchRequest.Controls, pagingControl)
260
+	} else {
261
+		castControl, ok := control.(*ControlPaging)
262
+		if !ok {
263
+			return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
264
+		}
265
+		if castControl.PagingSize != pagingSize {
266
+			return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
267
+		}
268
+		pagingControl = castControl
269
+	}
270
+
271
+	searchResult := new(SearchResult)
272
+	for {
273
+		result, err := l.Search(searchRequest)
274
+		l.Debug.Printf("Looking for Paging Control...")
275
+		if err != nil {
276
+			return searchResult, err
277
+		}
278
+		if result == nil {
279
+			return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
280
+		}
281
+
282
+		for _, entry := range result.Entries {
283
+			searchResult.Entries = append(searchResult.Entries, entry)
284
+		}
285
+		for _, referral := range result.Referrals {
286
+			searchResult.Referrals = append(searchResult.Referrals, referral)
287
+		}
288
+		for _, control := range result.Controls {
289
+			searchResult.Controls = append(searchResult.Controls, control)
290
+		}
291
+
292
+		l.Debug.Printf("Looking for Paging Control...")
293
+		pagingResult := FindControl(result.Controls, ControlTypePaging)
294
+		if pagingResult == nil {
295
+			pagingControl = nil
296
+			l.Debug.Printf("Could not find paging control.  Breaking...")
297
+			break
298
+		}
299
+
300
+		cookie := pagingResult.(*ControlPaging).Cookie
301
+		if len(cookie) == 0 {
302
+			pagingControl = nil
303
+			l.Debug.Printf("Could not find cookie.  Breaking...")
304
+			break
305
+		}
306
+		pagingControl.SetCookie(cookie)
307
+	}
308
+
309
+	if pagingControl != nil {
310
+		l.Debug.Printf("Abandoning Paging...")
311
+		pagingControl.PagingSize = 0
312
+		l.Search(searchRequest)
313
+	}
314
+
315
+	return searchResult, nil
316
+}
317
+
318
+// Search performs the given search request
319
+func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
320
+	msgCtx, err := l.doRequest(searchRequest)
321
+	if err != nil {
322
+		return nil, err
323
+	}
324
+	defer l.finishMessage(msgCtx)
325
+
326
+	result := &SearchResult{
327
+		Entries:   make([]*Entry, 0),
328
+		Referrals: make([]string, 0),
329
+		Controls:  make([]Control, 0)}
330
+
331
+	for {
332
+		packet, err := l.readPacket(msgCtx)
333
+		if err != nil {
334
+			return nil, err
335
+		}
336
+
337
+		switch packet.Children[1].Tag {
338
+		case 4:
339
+			entry := new(Entry)
340
+			entry.DN = packet.Children[1].Children[0].Value.(string)
341
+			for _, child := range packet.Children[1].Children[1].Children {
342
+				attr := new(EntryAttribute)
343
+				attr.Name = child.Children[0].Value.(string)
344
+				for _, value := range child.Children[1].Children {
345
+					attr.Values = append(attr.Values, value.Value.(string))
346
+					attr.ByteValues = append(attr.ByteValues, value.ByteValue)
347
+				}
348
+				entry.Attributes = append(entry.Attributes, attr)
349
+			}
350
+			result.Entries = append(result.Entries, entry)
351
+		case 5:
352
+			err := GetLDAPError(packet)
353
+			if err != nil {
354
+				return nil, err
355
+			}
356
+			if len(packet.Children) == 3 {
357
+				for _, child := range packet.Children[2].Children {
358
+					decodedChild, err := DecodeControl(child)
359
+					if err != nil {
360
+						return nil, fmt.Errorf("failed to decode child control: %s", err)
361
+					}
362
+					result.Controls = append(result.Controls, decodedChild)
363
+				}
364
+			}
365
+			return result, nil
366
+		case 19:
367
+			result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
368
+		}
369
+	}
370
+}

+ 19
- 0
vendor/github.com/goshuirc/e-nfa/.travis.yml View File

@@ -0,0 +1,19 @@
1
+language: go
2
+
3
+go:
4
+    - 1.4
5
+    - tip
6
+
7
+before_install:
8
+    - go get golang.org/x/tools/cmd/cover
9
+    - go get golang.org/x/tools/cmd/vet
10
+    - go get golang.org/x/tools/cmd/goimports
11
+    - go get github.com/golang/lint/golint
12
+    - go get github.com/mattn/goveralls
13
+
14
+script:
15
+    - go vet ./...
16
+#    - $HOME/gopath/bin/goveralls -coverprofile=coverage.cov -service=travis-ci
17
+#    - bash <(curl -s https://codecov.io/bash)
18
+    - go test -bench=. -benchmem ./...
19
+    #- sh ./install_all_cmd.sh

+ 122
- 0
vendor/github.com/goshuirc/e-nfa/README.md View File

@@ -0,0 +1,122 @@
1
+ε-NFA: Epsilon-Nondeterministic finite automaton
2
+==============
3
+
4
+[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kkdai/e-nfa/master/LICENSE)  [![GoDoc](https://godoc.org/github.com/kkdai/e-nfa?status.svg)](https://godoc.org/github.com/kkdai/e-nfa)  [![Build Status](https://travis-ci.org/kkdai/e-nfa.svg?branch=master)](https://travis-ci.org/kkdai/e-nfa)
5
+
6
+
7
+
8
+![image](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/NFAexample.svg/250px-NFAexample.svg.png)
9
+
10
+
11
+
12
+What is Epsilon-Nondeterministic finite automaton
13
+=============
14
+
15
+`ε-NFA`: Epsilon-Nondeterministic finite automaton (so call:Nondeterministic finite automaton with ε-moves)
16
+
17
+In the automata theory, a nondeterministic finite automaton with ε-moves (NFA-ε)(also known as NFA-λ) is an extension of nondeterministic finite automaton(NFA), which allows a transformation to a new state without consuming any input symbols. The transitions without consuming an input symbol are called ε-transitions or λ-transitions. In the state diagrams, they are usually labeled with the Greek letter ε or λ.
18
+
19
+(sited from [here](https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton))
20
+
21
+
22
+Looking for DFA implement?
23
+=============
24
+
25
+I also write a DFA implenent in Go here. [https://github.com/kkdai/dfa](https://github.com/kkdai/dfa)
26
+
27
+Looking for NFA implement?
28
+=============
29
+
30
+I also write a NFA implenent in Go here. [https://github.com/kkdai/nfa](https://github.com/kkdai/nfa)
31
+
32
+
33
+Installation and Usage
34
+=============
35
+
36
+
37
+Install
38
+---------------
39
+
40
+    go get github.com/kkdai/e-nfa
41
+
42
+
43
+
44
+Usage
45
+---------------
46
+
47
+Following is sample code to implement a epsilon-NFA automata diagram as follow:
48
+
49
+![image](image/eNFA.png)
50
+
51
+
52
+
53
+```go
54
+
55
+package main
56
+
57
+import (
58
+    "github.com/kkdai/enfa"
59
+    "fmt"
60
+)
61
+
62
+func main() {
63
+
64
+	nfa := NewENFA(0, false)
65
+	nfa.AddState(1, false)
66
+	nfa.AddState(2, false)
67
+	nfa.AddState(3, true)
68
+	nfa.AddState(4, false)
69
+	nfa.AddState(5, false)
70
+
71
+	nfa.AddTransition(0, "1", 1)
72
+	nfa.AddTransition(0, "0", 4)
73
+
74
+	nfa.AddTransition(1, "1", 2)
75
+	nfa.AddTransition(1, "", 3) //epsilon
76
+	nfa.AddTransition(2, "1", 3)
77
+	nfa.AddTransition(4, "0", 5)
78
+	nfa.AddTransition(4, "", 1, 2) //E -> epsilon B C
79
+	nfa.AddTransition(5, "0", 3)
80
+
81
+	nfa.PrintTransitionTable()
82
+
83
+	if !nfa.VerifyInputs([]string{"1"}) {
84
+		fmt.Printf("Verify inputs is failed")
85
+	}
86
+
87
+	nfa.Reset()
88
+
89
+	if !nfa.VerifyInputs([]string{"1", "1", "1"}) {
90
+		fmt.Printf("Verify inputs is failed")
91
+	}
92
+
93
+	nfa.Reset()
94
+
95
+	if !nfa.VerifyInputs([]string{"0", "1"}) {
96
+		fmt.Printf"Verify inputs is failed")
97
+	}
98
+
99
+	nfa.Reset()
100
+	if !nfa.VerifyInputs([]string{"0", "0", "0"}) {
101
+		fmt.Printf("Verify inputs is failed")
102
+	}
103
+}
104
+
105
+```
106
+
107
+Inspired By
108
+=============
109
+
110
+- [ε-NFA: Wiki](https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton_with_%CE%B5-moves)
111
+- [Coursera: Automata](https://class.coursera.org/automata-004/)
112
+
113
+Project52
114
+---------------
115
+
116
+It is one of my [project 52](https://github.com/kkdai/project52).
117
+
118
+
119
+License
120
+---------------
121
+
122
+This package is licensed under MIT license. See LICENSE for details.

+ 185
- 0
vendor/github.com/goshuirc/e-nfa/enfa.go View File

@@ -0,0 +1,185 @@
1
+package enfa
2
+
3
+import "fmt"
4
+
5
+type transitionInput struct {
6
+	srcState int
7
+	input    string
8
+}
9
+
10
+type destState map[int]bool
11
+
12
+type ENFA struct {
13
+	initState    int
14
+	currentState map[int]bool
15
+	totalStates  []int
16
+	finalStates  []int
17
+	transition   map[transitionInput]destState
18
+	inputMap     map[string]bool
19
+}
20
+
21
+//New a new NFA
22
+func NewENFA(initState int, isFinal bool) *ENFA {
23
+
24
+	retNFA := &ENFA{
25
+		transition: make(map[transitionInput]destState),
26
+		inputMap:   make(map[string]bool),
27
+		initState:  initState}
28
+
29
+	retNFA.currentState = make(map[int]bool)
30
+	retNFA.currentState[initState] = true
31
+	retNFA.AddState(initState, isFinal)
32
+	return retNFA
33
+}
34
+
35
+//Add new state in this NFA
36
+func (d *ENFA) AddState(state int, isFinal bool) {
37
+	if state == -1 {
38
+		fmt.Println("Cannot add state as -1, it is dead state")
39
+		return
40
+	}
41
+
42
+	d.totalStates = append(d.totalStates, state)
43
+	if isFinal {
44
+		d.finalStates = append(d.finalStates, state)
45
+	}
46
+}
47
+
48
+//Add new transition function into NFA
49
+func (d *ENFA) AddTransition(srcState int, input string, dstStateList ...int) {
50
+	find := false
51
+
52
+	//find input if exist in NFA input List
53
+	if _, ok := d.inputMap[input]; !ok {
54
+		//not exist, new input in this NFA
55
+		d.inputMap[input] = true
56
+	}
57
+
58
+	for _, v := range d.totalStates {
59
+		if v == srcState {
60
+			find = true
61
+		}
62
+	}
63
+
64
+	if !find {
65
+		fmt.Println("No such state:", srcState, " in current NFA")
66
+		return
67
+	}
68
+
69
+	dstMap := make(map[int]bool)
70
+	for _, destState := range dstStateList {
71
+		dstMap[destState] = true
72
+	}
73
+
74
+	targetTrans := transitionInput{srcState: srcState, input: input}
75
+	d.transition[targetTrans] = dstMap
76
+}
77
+
78
+func (d *ENFA) CheckPathExist(src int, input string, dst int) bool {
79
+	retMap, _ := d.transition[transitionInput{srcState: src, input: input}]
80
+	if _, ok := retMap[dst]; ok {
81
+		return true
82
+	}
83
+	return false
84
+}
85
+
86
+func (d *ENFA) Input(testInput string) []int {
87
+	updateCurrentState := make(map[int]bool)
88
+	for current, _ := range d.currentState {
89
+		for _, realTestInput := range []string{testInput, "*", "?"} {
90
+			intputTrans := transitionInput{srcState: current, input: realTestInput}
91
+			valMap, ok := d.transition[intputTrans]
92
+			if ok {
93
+				for dst, _ := range valMap {
94
+					updateCurrentState[dst] = true
95
+
96
+					//Update epsilon input way... if exist
97
+					epsilonTrans := transitionInput{srcState: dst}
98
+					if eMap, ok := d.transition[epsilonTrans]; ok {
99
+						for eDst, _ := range eMap {
100
+							updateCurrentState[eDst] = true
101
+						}
102
+					}
103
+				}
104
+			} else {
105
+				//dead state, remove in current state
106
+				//do nothing.
107
+			}
108
+		}
109
+	}
110
+
111
+	//update curret state
112
+	d.currentState = updateCurrentState
113
+
114
+	//return result
115
+	var ret []int
116
+	for state, _ := range updateCurrentState {
117
+		ret = append(ret, state)
118
+	}
119
+	return ret
120
+}
121
+
122
+//To verify current state if it is final state
123
+func (d *ENFA) Verify() bool {
124
+	for _, val := range d.finalStates {
125
+		for cState, _ := range d.currentState {
126
+			if val == cState {
127
+				return true
128
+			}
129
+		}
130
+	}
131
+	return false
132
+}
133
+
134
+//Reset NFA state to initilize state, but all state and transition function will remain
135
+func (d *ENFA) Reset() {
136
+	initState := make(map[int]bool)
137
+	initState[d.initState] = true
138
+	d.currentState = initState
139
+}
140
+
141
+//Verify if list of input could be accept by NFA or not
142
+func (d *ENFA) VerifyInputs(inputs []string) bool {
143
+	for _, v := range inputs {
144
+		d.Input(v)
145
+	}
146
+	return d.Verify()
147
+}
148
+
149
+//To print detail transition table contain of current NFA
150
+func (d *ENFA) PrintTransitionTable() {
151
+	fmt.Println("===================================================")
152
+	//list all inputs
153
+	var inputList []string
154
+	for key, _ := range d.inputMap {
155
+		if key == "" {
156
+			fmt.Printf("\tε|")
157
+		} else {
158
+			fmt.Printf("\t%s|", key)
159
+		}
160
+		inputList = append(inputList, key)
161
+	}
162
+
163
+	fmt.Printf("\n")
164
+	fmt.Println("---------------------------------------------------")
165
+
166
+	for _, state := range d.totalStates {
167
+		fmt.Printf("%d |", state)
168
+		for _, key := range inputList {
169
+			checkInput := transitionInput{srcState: state, input: key}
170
+			if dstState, ok := d.transition[checkInput]; ok {
171
+				fmt.Printf("\t")
172
+				for val, _ := range dstState {
173
+					fmt.Printf("%d,", val)
174
+				}
175
+				fmt.Printf("|")
176
+			} else {
177
+				fmt.Printf("\tNA|")
178
+			}
179
+		}
180
+		fmt.Printf("\n")
181
+	}
182
+
183
+	fmt.Println("---------------------------------------------------")
184
+	fmt.Println("===================================================")
185
+}

+ 13
- 0
vendor/github.com/goshuirc/irc-go/LICENSE View File

@@ -0,0 +1,13 @@
1
+Copyright (c) 2016-2017 Daniel Oaks
2
+
3
+Permission to use, copy, modify, and/or distribute this software for any
4
+purpose with or without fee is hereby granted, provided that the above
5
+copyright notice and this permission notice appear in all copies.
6
+
7
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+PERFORMANCE OF THIS SOFTWARE.

+ 86
- 0
vendor/github.com/goshuirc/irc-go/ircfmt/doc.go View File

@@ -0,0 +1,86 @@
1
+// written by Daniel Oaks <daniel@danieloaks.net>
2
+// released under the ISC license
3
+
4
+/*
5
+Package ircfmt handles IRC formatting codes, escaping and unescaping.
6
+
7
+This allows for a simpler representation of strings that contain colour codes,
8
+bold codes, and such, without having to write and handle raw bytes when
9
+assembling outgoing messages.
10
+
11
+This lets you turn raw IRC messages into our escaped versions, and turn escaped
12
+versions back into raw messages suitable for sending on IRC connections. This
13
+is designed to be used on things like PRIVMSG / NOTICE commands, MOTD blocks,
14
+and such.
15
+
16
+The escape character we use in this library is the dollar sign ("$"), along
17
+with the given escape characters:
18
+
19
+	--------------------------------
20
+	 Name           | Escape | Raw
21
+	--------------------------------
22
+	 Dollarsign     |   $$   |  $
23
+	 Bold           |   $b   | 0x02
24
+	 Colour         |   $c   | 0x03
25
+	 Monospace      |   $m   | 0x11
26
+	 Reverse Colour |   $v   | 0x16
27
+	 Italic         |   $i   | 0x1d
28
+	 Strikethrough  |   $s   | 0x1e
29
+	 Underscore     |   $u   | 0x1f
30
+	 Reset          |   $r   | 0x0f
31
+	--------------------------------
32
+
33
+Colours are escaped in a slightly different way, using the actual names of them
34
+rather than just the raw numbers.
35
+
36
+In our escaped format, the colours for the fore and background are contained in
37
+square brackets after the colour ("$c") escape. For example:
38
+
39
+	Red foreground:
40
+		Escaped:  This is a $c[red]cool message!
41
+		Raw:      This is a 0x034cool message!
42
+
43
+	Blue foreground, green background:
44
+		Escaped:  This is a $c[blue,green]rad message!
45
+		Raw:      This is a 0x032,3rad message!
46
+
47
+When assembling a raw message, we make sure to use the full colour code
48
+("02" vs just "2") when it could become confused due to numbers just after the
49
+colour escape code. For instance, lines like this will be unescaped correctly:
50
+
51
+	No number after colour escape:
52
+		Escaped:  This is a $c[red]cool message!
53
+		Raw:      This is a 0x034cool message!
54
+
55
+	Number after colour escape:
56
+		Escaped:  This is $c[blue]20% cooler!
57
+		Raw:      This is 0x030220% cooler
58
+
59
+Here are the colour names and codes we recognise:
60
+
61
+	--------------------
62
+	 Code | Name
63
+	--------------------
64
+	  00  | white
65
+	  01  | black
66
+	  02  | blue
67
+	  03  | green
68
+	  04  | red
69
+	  05  | brown
70
+	  06  | magenta
71
+	  07  | orange
72
+	  08  | yellow
73
+	  09  | light green
74
+	  10  | cyan
75
+	  11  | light cyan
76
+	  12  | light blue
77
+	  13  | pink
78
+	  14  | grey
79
+	  15  | light grey
80
+	  99  | default
81
+	--------------------
82
+
83
+These other colours aren't given names:
84
+https://modern.ircdocs.horse/formatting.html#colors-16-98
85
+*/
86
+package ircfmt

+ 330
- 0
vendor/github.com/goshuirc/irc-go/ircfmt/ircfmt.go View File

@@ -0,0 +1,330 @@
1
+// written by Daniel Oaks <daniel@danieloaks.net>
2
+// released under the ISC license
3
+
4
+package ircfmt
5
+
6
+import (
7
+	"strings"
8
+)
9
+
10
+const (
11
+	// raw bytes and strings to do replacing with
12
+	bold          string = "\x02"
13
+	colour        string = "\x03"
14
+	monospace     string = "\x11"
15
+	reverseColour string = "\x16"
16
+	italic        string = "\x1d"
17
+	strikethrough string = "\x1e"
18
+	underline     string = "\x1f"
19
+	reset         string = "\x0f"
20
+
21
+	runecolour        rune = '\x03'
22
+	runebold          rune = '\x02'
23
+	runemonospace     rune = '\x11'
24
+	runereverseColour rune = '\x16'
25
+	runeitalic        rune = '\x1d'
26
+	runestrikethrough rune = '\x1e'
27
+	runereset         rune = '\x0f'
28
+	runeunderline     rune = '\x1f'
29
+
30
+	// valid characters in a colour code character, for speed
31
+	colours1 string = "0123456789"
32
+)
33
+
34
+var (
35
+	// valtoescape replaces most of IRC characters with our escapes.
36
+	valtoescape = strings.NewReplacer("$", "$$", colour, "$c", reverseColour, "$v", bold, "$b", italic, "$i", strikethrough, "$s", underline, "$u", monospace, "$m", reset, "$r")
37
+	// valToStrip replaces most of the IRC characters with nothing
38
+	valToStrip = strings.NewReplacer(colour, "$c", reverseColour, "", bold, "", italic, "", strikethrough, "", underline, "", monospace, "", reset, "")
39
+
40
+	// escapetoval contains most of our escapes and how they map to real IRC characters.
41
+	// intentionally skips colour, since that's handled elsewhere.
42
+	escapetoval = map[rune]string{
43
+		'$': "$",
44
+		'b': bold,
45
+		'i': italic,
46
+		'v': reverseColour,
47
+		's': strikethrough,
48
+		'u': underline,
49
+		'm': monospace,
50
+		'r': reset,
51
+	}
52
+
53
+	// valid colour codes
54
+	numtocolour = map[string]string{
55
+		"99": "default",
56
+		"15": "light grey",
57
+		"14": "grey",
58
+		"13": "pink",
59
+		"12": "light blue",
60
+		"11": "light cyan",
61
+		"10": "cyan",
62
+		"09": "light green",
63
+		"08": "yellow",
64
+		"07": "orange",
65
+		"06": "magenta",
66
+		"05": "brown",
67
+		"04": "red",
68
+		"03": "green",
69
+		"02": "blue",
70
+		"01": "black",
71
+		"00": "white",
72
+		"9":  "light green",
73
+		"8":  "yellow",
74
+		"7":  "orange",
75
+		"6":  "magenta",
76
+		"5":  "brown",
77
+		"4":  "red",
78
+		"3":  "green",
79
+		"2":  "blue",
80
+		"1":  "black",
81
+		"0":  "white",
82
+	}
83
+
84
+	// full and truncated colour codes
85
+	colourcodesFull = map[string]string{
86
+		"white":       "00",
87
+		"black":       "01",
88
+		"blue":        "02",
89
+		"green":       "03",
90
+		"red":         "04",
91
+		"brown":       "05",
92
+		"magenta":     "06",
93
+		"orange":      "07",
94
+		"yellow":      "08",
95
+		"light green": "09",
96
+		"cyan":        "10",
97
+		"light cyan":  "11",
98
+		"light blue":  "12",
99
+		"pink":        "13",
100
+		"grey":        "14",
101
+		"light grey":  "15",
102
+		"default":     "99",
103
+	}
104
+	colourcodesTruncated = map[string]string{
105
+		"white":       "0",
106
+		"black":       "1",
107
+		"blue":        "2",
108
+		"green":       "3",
109
+		"red":         "4",
110
+		"brown":       "5",
111
+		"magenta":     "6",
112
+		"orange":      "7",
113
+		"yellow":      "8",
114
+		"light green": "9",
115
+		"cyan":        "10",
116
+		"light cyan":  "11",
117
+		"light blue":  "12",
118
+		"pink":        "13",
119
+		"grey":        "14",
120
+		"light grey":  "15",
121
+		"default":     "99",
122
+	}
123
+)
124
+
125
+// Escape takes a raw IRC string and returns it with our escapes.
126
+//
127
+// IE, it turns this: "This is a \x02cool\x02, \x034red\x0f message!"
128
+// into: "This is a $bcool$b, $c[red]red$r message!"
129
+func Escape(in string) string {
130
+	// replace all our usual escapes
131
+	in = valtoescape.Replace(in)
132
+
133
+	inRunes := []rune(in)
134
+	//var out string
135
+	out := strings.Builder{}
136
+	for 0 < len(inRunes) {
137
+		if 1 < len(inRunes) && inRunes[0] == '$' && inRunes[1] == 'c' {
138
+			// handle colours
139
+			out.WriteString("$c")
140
+			inRunes = inRunes[2:] // strip colour code chars
141
+
142
+			if len(inRunes) < 1 || !strings.Contains(colours1, string(inRunes[0])) {
143
+				out.WriteString("[]")
144
+				continue
145
+			}
146
+
147
+			var foreBuffer, backBuffer string
148
+			foreBuffer += string(inRunes[0])
149
+			inRunes = inRunes[1:]
150
+			if 0 < len(inRunes) && strings.Contains(colours1, string(inRunes[0])) {
151
+				foreBuffer += string(inRunes[0])
152
+				inRunes = inRunes[1:]
153
+			}
154
+			if 1 < len(inRunes) && inRunes[0] == ',' && strings.Contains(colours1, string(inRunes[1])) {
155
+				backBuffer += string(inRunes[1])
156
+				inRunes = inRunes[2:]
157
+				if 0 < len(inRunes) && strings.Contains(colours1, string(inRunes[0])) {
158
+					backBuffer += string(inRunes[0])
159
+					inRunes = inRunes[1:]
160
+				}
161
+			}
162
+
163
+			foreName, exists := numtocolour[foreBuffer]
164
+			if !exists {
165
+				foreName = foreBuffer
166
+			}
167
+			backName, exists := numtocolour[backBuffer]
168
+			if !exists {
169
+				backName = backBuffer
170
+			}
171
+
172
+			out.WriteRune('[')
173
+			out.WriteString(foreName)
174
+			if backName != "" {
175
+				out.WriteRune(',')
176
+				out.WriteString(backName)
177
+			}
178
+			out.WriteRune(']')
179
+
180
+		} else {
181
+			// special case for $$c
182
+			if len(inRunes) > 2 && inRunes[0] == '$' && inRunes[1] == '$' && inRunes[2] == 'c' {
183
+				out.WriteRune(inRunes[0])
184
+				out.WriteRune(inRunes[1])
185
+				out.WriteRune(inRunes[2])
186
+				inRunes = inRunes[3:]
187
+			} else {
188
+				out.WriteRune(inRunes[0])
189
+				inRunes = inRunes[1:]
190
+			}
191
+		}
192
+	}
193
+
194
+	return out.String()
195
+}
196
+
197
+// Strip takes a raw IRC string and removes it with all formatting codes removed
198
+// IE, it turns this: "This is a \x02cool\x02, \x034red\x0f message!"
199
+// into: "This is a cool, red message!"
200
+func Strip(in string) string {
201
+	out := strings.Builder{}
202
+	runes := []rune(in)
203
+	if out.Len() < len(runes) { // Reduce allocations where needed
204
+		out.Grow(len(in) - out.Len())
205
+	}
206
+	for len(runes) > 0 {
207
+		switch runes[0] {
208
+		case runebold, runemonospace, runereverseColour, runeitalic, runestrikethrough, runeunderline, runereset:
209
+			runes = runes[1:]
210
+		case runecolour:
211
+			runes = removeColour(runes)
212
+		default:
213
+			out.WriteRune(runes[0])
214
+			runes = runes[1:]
215
+		}
216
+	}
217
+	return out.String()
218
+}
219
+
220
+func removeNumber(runes []rune) []rune {
221
+	if len(runes) > 0 && runes[0] >= '0' && runes[0] <= '9' {
222
+		runes = runes[1:]
223
+	}
224
+	return runes
225
+}
226
+
227
+func removeColour(runes []rune) []rune {
228
+	if runes[0] != runecolour {
229
+		return runes
230
+	}
231
+
232
+	runes = runes[1:]
233
+	runes = removeNumber(runes)
234
+	runes = removeNumber(runes)
235
+
236
+	if len(runes) > 1 && runes[0] == ',' && runes[1] >= '0' && runes[1] <= '9' {
237
+		runes = runes[2:]
238
+	} else {
239
+		return runes // Nothing else because we dont have a comma
240
+	}
241
+	runes = removeNumber(runes)
242
+	return runes
243
+}
244
+
245
+// Unescape takes our escaped string and returns a raw IRC string.
246
+//
247
+// IE, it turns this: "This is a $bcool$b, $c[red]red$r message!"
248
+// into this: "This is a \x02cool\x02, \x034red\x0f message!"
249
+func Unescape(in string) string {
250
+	out := strings.Builder{}
251
+
252
+	remaining := []rune(in)
253
+	for 0 < len(remaining) {
254
+		char := remaining[0]
255
+		remaining = remaining[1:]
256
+
257
+		if char == '$' && 0 < len(remaining) {
258
+			char = remaining[0]
259
+			remaining = remaining[1:]
260
+
261
+			val, exists := escapetoval[char]
262
+			if exists {
263
+				out.WriteString(val)
264
+			} else if char == 'c' {
265
+				out.WriteString(colour)
266
+
267
+				if len(remaining) < 2 || remaining[0] != '[' {
268
+					continue
269
+				}
270
+
271
+				// get colour names
272
+				var coloursBuffer string
273
+				remaining = remaining[1:]
274
+				for remaining[0] != ']' {
275
+					coloursBuffer += string(remaining[0])
276
+					remaining = remaining[1:]
277
+				}
278
+				remaining = remaining[1:] // strip final ']'
279
+
280
+				colours := strings.Split(coloursBuffer, ",")
281
+				var foreColour, backColour string
282
+				foreColour = colours[0]
283
+				if 1 < len(colours) {
284
+					backColour = colours[1]
285
+				}
286
+
287
+				// decide whether we can use truncated colour codes
288
+				canUseTruncated := len(remaining) < 1 || !strings.Contains(colours1, string(remaining[0]))
289
+
290
+				// turn colour names into real codes
291
+				var foreColourCode, backColourCode string
292
+				var exists bool
293
+
294
+				if backColour != "" || canUseTruncated {
295
+					foreColourCode, exists = colourcodesTruncated[foreColour]
296
+				} else {
297
+					foreColourCode, exists = colourcodesFull[foreColour]
298
+				}
299
+				if exists {
300
+					foreColour = foreColourCode
301
+				}
302
+
303
+				if backColour != "" {
304
+					if canUseTruncated {
305
+						backColourCode, exists = colourcodesTruncated[backColour]
306
+					} else {
307
+						backColourCode, exists = colourcodesFull[backColour]
308
+					}
309
+					if exists {
310
+						backColour = backColourCode
311
+					}
312
+				}
313
+
314
+				// output colour codes
315
+				out.WriteString(foreColour)
316
+				if backColour != "" {
317
+					out.WriteRune(',')
318
+					out.WriteString(backColour)
319
+				}
320
+			} else {
321
+				// unknown char
322
+				out.WriteRune(char)
323
+			}
324
+		} else {
325
+			out.WriteRune(char)
326
+		}
327
+	}
328
+
329
+	return out.String()
330
+}

+ 7
- 0
vendor/github.com/goshuirc/irc-go/ircmatch/doc.go View File

@@ -0,0 +1,7 @@
1
+// written by Daniel Oaks <daniel@danieloaks.net>
2
+// released under the ISC license
3
+
4
+/*
5
+Package ircmatch handles matching IRC strings with the traditional glob-like syntax.
6
+*/
7
+package ircmatch

+ 57
- 0
vendor/github.com/goshuirc/irc-go/ircmatch/ircmatch.go View File

@@ -0,0 +1,57 @@
1
+package ircmatch
2
+
3
+import enfa "github.com/goshuirc/e-nfa"
4
+
5
+// Matcher represents an object that can match IRC strings.
6
+type Matcher struct {
7
+	internalENFA *enfa.ENFA
8
+}
9
+
10
+// MakeMatch creates a Matcher.
11
+func MakeMatch(globTemplate string) Matcher {
12
+	var newmatch Matcher
13
+
14
+	// assemble internal enfa
15
+	newmatch.internalENFA = enfa.NewENFA(0, false)
16
+
17
+	var currentState int
18
+	var lastWasStar bool
19
+	for _, char := range globTemplate {
20
+		if char == '*' {
21
+			if lastWasStar {
22
+				continue
23
+			}
24
+			newmatch.internalENFA.AddTransition(currentState, "*", currentState)
25
+			lastWasStar = true
26
+			continue
27
+		} else if char == '?' {
28
+			newmatch.internalENFA.AddState(currentState+1, false)
29
+			newmatch.internalENFA.AddTransition(currentState, "?", currentState+1)
30
+			currentState++
31
+		} else {
32
+			newmatch.internalENFA.AddState(currentState+1, false)
33
+			newmatch.internalENFA.AddTransition(currentState, string(char), currentState+1)
34
+			currentState++
35
+		}
36
+
37
+		lastWasStar = false
38
+	}
39
+
40
+	// create end state
41
+	newmatch.internalENFA.AddState(currentState+1, true)
42
+	newmatch.internalENFA.AddTransition(currentState, "", currentState+1)
43
+
44
+	return newmatch
45
+}
46
+
47
+// Match returns true if the given string matches this glob.
48
+func (menfa *Matcher) Match(search string) bool {
49
+	var searchChars []string
50
+	for _, char := range search {
51
+		searchChars = append(searchChars, string(char))
52
+	}
53
+
54
+	isMatch := menfa.internalENFA.VerifyInputs(searchChars)
55
+	menfa.internalENFA.Reset()
56
+	return isMatch
57
+}

+ 7
- 0
vendor/github.com/goshuirc/irc-go/ircmsg/doc.go View File

@@ -0,0 +1,7 @@
1
+// written by Daniel Oaks <daniel@danieloaks.net>
2
+// released under the ISC license
3
+
4
+/*
5
+Package ircmsg helps parse and create lines for IRC connections.
6
+*/
7
+package ircmsg

+ 401
- 0
vendor/github.com/goshuirc/irc-go/ircmsg/message.go View File

@@ -0,0 +1,401 @@
1
+// Copyright (c) 2016-2019 Daniel Oaks <daniel@danieloaks.net>
2
+// Copyright (c) 2018-2019 Shivaram Lingamneni <slingamn@cs.stanford.edu>
3
+
4
+// released under the ISC license
5
+
6
+package ircmsg
7
+
8
+import (
9
+	"bytes"
10
+	"errors"
11
+	"strings"
12
+)
13
+
14
+const (
15
+	// "The size limit for message tags is 8191 bytes, including the leading
16
+	//  '@' (0x40) and trailing space ' ' (0x20) characters."
17
+	MaxlenTags = 8191
18
+
19
+	// MaxlenTags - ('@' + ' ')
20
+	MaxlenTagData = MaxlenTags - 2
21
+
22
+	// "Clients MUST NOT send messages with tag data exceeding 4094 bytes,
23
+	//  this includes tags with or without the client-only prefix."
24
+	MaxlenClientTagData = 4094
25
+
26
+	// "Servers MUST NOT add tag data exceeding 4094 bytes to messages."
27
+	MaxlenServerTagData = 4094
28
+
29
+	// '@' + MaxlenClientTagData + ' '
30
+	// this is the analogue of MaxlenTags when the source of the message is a client
31
+	MaxlenTagsFromClient = MaxlenClientTagData + 2
32
+)
33
+
34
+var (
35
+	// ErrorLineIsEmpty indicates that the given IRC line was empty.
36
+	ErrorLineIsEmpty = errors.New("Line is empty")
37
+	// ErrorLineContainsBadChar indicates that the line contained invalid characters
38
+	ErrorLineContainsBadChar = errors.New("Line contains invalid characters")
39
+	// ErrorLineTooLong indicates that the message exceeded the maximum tag length
40
+	// (the name references 417 ERR_INPUTTOOLONG; we reserve the right to return it
41
+	// for messages that exceed the non-tag length limit)
42
+	ErrorLineTooLong = errors.New("Line could not be parsed because a specified length limit was exceeded")
43
+
44
+	ErrorCommandMissing = errors.New("IRC messages MUST have a command")
45
+	ErrorBadParam       = errors.New("Cannot have an empty param, a param with spaces, or a param that starts with ':' before the last parameter")
46
+)
47
+
48
+// IrcMessage represents an IRC message, as defined by the RFCs and as
49
+// extended by the IRCv3 Message Tags specification with the introduction
50
+// of message tags.
51
+type IrcMessage struct {
52
+	Prefix         string
53
+	Command        string
54
+	Params         []string
55
+	tags           map[string]string
56
+	clientOnlyTags map[string]string
57
+}
58
+
59
+// GetTag returns whether a tag is present, and if so, what its value is.
60
+func (msg *IrcMessage) GetTag(tagName string) (present bool, value string) {
61
+	if len(tagName) == 0 {
62
+		return
63
+	} else if tagName[0] == '+' {
64
+		value, present = msg.clientOnlyTags[tagName]
65
+		return
66
+	} else {
67
+		value, present = msg.tags[tagName]
68
+		return
69
+	}
70
+}
71
+
72
+// HasTag returns whether a tag is present.
73
+func (msg *IrcMessage) HasTag(tagName string) (present bool) {
74
+	present, _ = msg.GetTag(tagName)
75
+	return
76
+}
77
+
78
+// SetTag sets a tag.
79
+func (msg *IrcMessage) SetTag(tagName, tagValue string) {
80
+	if len(tagName) == 0 {
81
+		return
82
+	} else if tagName[0] == '+' {
83
+		if msg.clientOnlyTags == nil {
84
+			msg.clientOnlyTags = make(map[string]string)
85
+		}
86
+		msg.clientOnlyTags[tagName] = tagValue
87
+	} else {
88
+		if msg.tags == nil {
89
+			msg.tags = make(map[string]string)
90
+		}
91
+		msg.tags[tagName] = tagValue
92
+	}
93
+}
94
+
95
+// DeleteTag deletes a tag.
96
+func (msg *IrcMessage) DeleteTag(tagName string) {
97
+	if len(tagName) == 0 {
98
+		return
99
+	} else if tagName[0] == '+' {
100
+		delete(msg.clientOnlyTags, tagName)
101
+	} else {
102
+		delete(msg.tags, tagName)
103
+	}
104
+}
105
+
106
+// UpdateTags is a convenience to set multiple tags at once.
107
+func (msg *IrcMessage) UpdateTags(tags map[string]string) {
108
+	for name, value := range tags {
109
+		msg.SetTag(name, value)
110
+	}
111
+}
112
+
113
+// AllTags returns all tags as a single map.
114
+func (msg *IrcMessage) AllTags() (result map[string]string) {
115
+	result = make(map[string]string, len(msg.tags)+len(msg.clientOnlyTags))
116
+	for name, value := range msg.tags {
117
+		result[name] = value
118
+	}
119
+	for name, value := range msg.clientOnlyTags {
120
+		result[name] = value
121
+	}
122
+	return
123
+}
124
+
125
+// ClientOnlyTags returns the client-only tags (the tags with the + prefix).
126
+// The returned map may be internal storage of the IrcMessage object and
127
+// should not be modified.
128
+func (msg *IrcMessage) ClientOnlyTags() map[string]string {
129
+	return msg.clientOnlyTags
130
+}
131
+
132
+// ParseLine creates and returns a message from the given IRC line.
133
+func ParseLine(line string) (ircmsg IrcMessage, err error) {
134
+	return parseLine(line, 0, 0)
135
+}
136
+
137
+// ParseLineStrict creates and returns an IrcMessage from the given IRC line,
138
+// taking the maximum length into account and truncating the message as appropriate.
139
+// If fromClient is true, it enforces the client limit on tag data length (4094 bytes),
140
+// allowing the server to return ERR_INPUTTOOLONG as appropriate. If truncateLen is
141
+// nonzero, it is the length at which the non-tag portion of the message is truncated.
142
+func ParseLineStrict(line string, fromClient bool, truncateLen int) (ircmsg IrcMessage, err error) {
143
+	maxTagDataLength := MaxlenTagData
144
+	if fromClient {
145
+		maxTagDataLength = MaxlenClientTagData
146
+	}
147
+	return parseLine(line, maxTagDataLength, truncateLen)
148
+}
149
+
150
+// slice off any amount of ' ' from the front of the string
151
+func trimInitialSpaces(str string) string {
152
+	var i int
153
+	for i = 0; i < len(str) && str[i] == ' '; i += 1 {
154
+	}
155
+	return str[i:]
156
+}
157
+
158
+func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg IrcMessage, err error) {
159
+	if strings.IndexByte(line, '\x00') != -1 {
160
+		err = ErrorLineContainsBadChar
161
+		return
162
+	}
163
+
164
+	// trim to the first appearance of either '\r' or '\n':
165
+	lineEnd := strings.IndexByte(line, '\r')
166
+	newlineIndex := strings.IndexByte(line, '\n')
167
+	if newlineIndex != -1 && (lineEnd == -1 || newlineIndex < lineEnd) {
168
+		lineEnd = newlineIndex
169
+	}
170
+	if lineEnd != -1 {
171
+		line = line[:lineEnd]
172
+	}
173
+
174
+	if len(line) < 1 {
175
+		return ircmsg, ErrorLineIsEmpty
176
+	}
177
+
178
+	// tags
179
+	if line[0] == '@' {
180
+		tagEnd := strings.IndexByte(line, ' ')
181
+		if tagEnd == -1 {
182
+			return ircmsg, ErrorLineIsEmpty
183
+		}
184
+		tags := line[1:tagEnd]
185
+		if 0 < maxTagDataLength && maxTagDataLength < len(tags) {
186
+			return ircmsg, ErrorLineTooLong
187
+		}
188
+		err = ircmsg.parseTags(tags)
189
+		if err != nil {
190
+			return
191
+		}
192
+		// skip over the tags and the separating space
193
+		line = line[tagEnd+1:]
194
+	}
195
+
196
+	// truncate if desired
197
+	if 0 < truncateLen && truncateLen < len(line) {
198
+		line = line[:truncateLen]
199
+	}
200
+
201
+	// modern: "These message parts, and parameters themselves, are separated
202
+	// by one or more ASCII SPACE characters"
203
+	line = trimInitialSpaces(line)
204
+
205
+	// prefix
206
+	if 0 < len(line) && line[0] == ':' {
207
+		prefixEnd := strings.IndexByte(line, ' ')
208
+		if prefixEnd == -1 {
209
+			return ircmsg, ErrorLineIsEmpty
210
+		}
211
+		ircmsg.Prefix = line[1:prefixEnd]
212
+		// skip over the prefix and the separating space
213
+		line = line[prefixEnd+1:]
214
+	}
215
+
216
+	line = trimInitialSpaces(line)
217
+
218
+	// command
219
+	commandEnd := strings.IndexByte(line, ' ')
220
+	paramStart := commandEnd + 1
221
+	if commandEnd == -1 {
222
+		commandEnd = len(line)
223
+		paramStart = len(line)
224
+	}
225
+	// normalize command to uppercase:
226
+	ircmsg.Command = strings.ToUpper(line[:commandEnd])
227
+	if len(ircmsg.Command) == 0 {
228
+		return ircmsg, ErrorLineIsEmpty
229
+	}
230
+	line = line[paramStart:]
231
+
232
+	for {
233
+		line = trimInitialSpaces(line)
234
+		if len(line) == 0 {
235
+			break
236
+		}
237
+		// handle trailing
238
+		if line[0] == ':' {
239
+			ircmsg.Params = append(ircmsg.Params, line[1:])
240
+			break
241
+		}
242
+		paramEnd := strings.IndexByte(line, ' ')
243
+		if paramEnd == -1 {
244
+			ircmsg.Params = append(ircmsg.Params, line)
245
+			break
246
+		}
247
+		ircmsg.Params = append(ircmsg.Params, line[:paramEnd])
248
+		line = line[paramEnd+1:]
249
+	}
250
+
251
+	return ircmsg, nil
252
+}
253
+
254
+// helper to parse tags
255
+func (ircmsg *IrcMessage) parseTags(tags string) (err error) {
256
+	for 0 < len(tags) {
257
+		tagEnd := strings.IndexByte(tags, ';')
258
+		endPos := tagEnd
259
+		nextPos := tagEnd + 1
260
+		if tagEnd == -1 {
261
+			endPos = len(tags)
262
+			nextPos = len(tags)
263
+		}
264
+		tagPair := tags[:endPos]
265
+		equalsIndex := strings.IndexByte(tagPair, '=')
266
+		var tagName, tagValue string
267
+		if equalsIndex == -1 {
268
+			// tag with no value
269
+			tagName = tagPair
270
+		} else {
271
+			tagName, tagValue = tagPair[:equalsIndex], tagPair[equalsIndex+1:]
272
+		}
273
+		ircmsg.SetTag(tagName, UnescapeTagValue(tagValue))
274
+		// skip over the tag just processed, plus the delimiting ; if any
275
+		tags = tags[nextPos:]
276
+	}
277
+	return nil
278
+}
279
+
280
+// MakeMessage provides a simple way to create a new IrcMessage.
281
+func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg IrcMessage) {
282
+	ircmsg.Prefix = prefix
283
+	ircmsg.Command = command
284
+	ircmsg.Params = params
285
+	ircmsg.UpdateTags(tags)
286
+	return ircmsg
287
+}
288
+
289
+// Line returns a sendable line created from an IrcMessage.
290
+func (ircmsg *IrcMessage) Line() (result string, err error) {
291
+	bytes, err := ircmsg.line(0, 0, 0, 0)
292
+	if err == nil {
293
+		result = string(bytes)
294
+	}
295
+	return
296
+}
297
+
298
+// LineBytes returns a sendable line created from an IrcMessage.
299
+func (ircmsg *IrcMessage) LineBytes() (result []byte, err error) {
300
+	result, err = ircmsg.line(0, 0, 0, 0)
301
+	return
302
+}
303
+
304
+// LineBytesStrict returns a sendable line, as a []byte, created from an IrcMessage.
305
+// fromClient controls whether the server-side or client-side tag length limit
306
+// is enforced. If truncateLen is nonzero, it is the length at which the
307
+// non-tag portion of the message is truncated.
308
+func (ircmsg *IrcMessage) LineBytesStrict(fromClient bool, truncateLen int) ([]byte, error) {
309
+	var tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit int
310
+	if fromClient {
311
+		// enforce client max tags:
312
+		// <client_max>   (4096)  :: '@' <tag_data 4094> ' '
313
+		tagLimit = MaxlenTagsFromClient
314
+	} else {
315
+		// on the server side, enforce separate client-only and server-added tag budgets:
316
+		// "Servers MUST NOT add tag data exceeding 4094 bytes to messages."
317
+		// <combined_max> (8191)  :: '@' <tag_data 4094> ';' <tag_data 4094> ' '
318
+		clientOnlyTagDataLimit = MaxlenClientTagData
319
+		serverAddedTagDataLimit = MaxlenServerTagData
320
+	}
321
+	return ircmsg.line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen)
322
+}
323
+
324
+// line returns a sendable line created from an IrcMessage.
325
+func (ircmsg *IrcMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) ([]byte, error) {
326
+	if len(ircmsg.Command) < 1 {
327
+		return nil, ErrorCommandMissing
328
+	}
329
+
330
+	var buf bytes.Buffer
331
+
332
+	// write the tags, computing the budgets for client-only tags and regular tags
333
+	var lenRegularTags, lenClientOnlyTags, lenTags int
334
+	if 0 < len(ircmsg.tags) || 0 < len(ircmsg.clientOnlyTags) {
335
+		buf.WriteByte('@')
336
+		firstTag := true
337
+		writeTags := func(tags map[string]string) {
338
+			for tag, val := range tags {
339
+				if !firstTag {
340
+					buf.WriteByte(';') // delimiter
341
+				}
342
+				buf.WriteString(tag)
343
+				if val != "" {
344
+					buf.WriteByte('=')
345
+					buf.WriteString(EscapeTagValue(val))
346
+				}
347
+				firstTag = false
348
+			}
349
+		}
350
+		writeTags(ircmsg.tags)
351
+		lenRegularTags = buf.Len() - 1 // '@' is not counted
352
+		writeTags(ircmsg.clientOnlyTags)
353
+		lenClientOnlyTags = (buf.Len() - 1) - lenRegularTags // '@' is not counted
354
+		if lenRegularTags != 0 {
355
+			// semicolon between regular and client-only tags is not counted
356
+			lenClientOnlyTags -= 1
357
+		}
358
+		buf.WriteByte(' ')
359
+	}
360
+	lenTags = buf.Len()
361
+
362
+	if 0 < tagLimit && tagLimit < buf.Len() {
363
+		return nil, ErrorLineTooLong
364
+	}
365
+	if (0 < clientOnlyTagDataLimit && clientOnlyTagDataLimit < lenClientOnlyTags) || (0 < serverAddedTagDataLimit && serverAddedTagDataLimit < lenRegularTags) {
366
+		return nil, ErrorLineTooLong
367
+	}
368
+
369
+	if len(ircmsg.Prefix) > 0 {
370
+		buf.WriteByte(':')
371
+		buf.WriteString(ircmsg.Prefix)
372
+		buf.WriteByte(' ')
373
+	}
374
+
375
+	buf.WriteString(ircmsg.Command)
376
+
377
+	for i, param := range ircmsg.Params {
378
+		buf.WriteByte(' ')
379
+		if len(param) < 1 || strings.IndexByte(param, ' ') != -1 || param[0] == ':' {
380
+			if i != len(ircmsg.Params)-1 {
381
+				return nil, ErrorBadParam
382
+			}
383
+			buf.WriteByte(':')
384
+		}
385
+		buf.WriteString(param)
386
+	}
387
+
388
+	// truncate if desired
389
+	// -2 for \r\n
390
+	restLen := buf.Len() - lenTags
391
+	if 0 < truncateLen && (truncateLen-2) < restLen {
392
+		buf.Truncate(lenTags + (truncateLen - 2))
393
+	}
394
+	buf.WriteString("\r\n")
395
+
396
+	result := buf.Bytes()
397
+	if bytes.IndexByte(result, '\x00') != -1 {
398
+		return nil, ErrorLineContainsBadChar
399
+	}
400
+	return result, nil
401
+}

+ 75
- 0
vendor/github.com/goshuirc/irc-go/ircmsg/tags.go View File

@@ -0,0 +1,75 @@
1
+// written by Daniel Oaks <daniel@danieloaks.net>
2
+// released under the ISC license
3
+
4
+package ircmsg
5
+
6
+import "bytes"
7
+import "strings"
8
+
9
+var (
10
+	// valtoescape replaces real characters with message tag escapes.
11
+	valtoescape = strings.NewReplacer("\\", "\\\\", ";", "\\:", " ", "\\s", "\r", "\\r", "\n", "\\n")
12
+
13
+	escapedCharLookupTable [256]byte
14
+)
15
+
16
+func init() {
17
+	// most chars escape to themselves
18
+	for i := 0; i < 256; i += 1 {
19
+		escapedCharLookupTable[i] = byte(i)
20
+	}
21
+	// these are the exceptions
22
+	escapedCharLookupTable[':'] = ';'
23
+	escapedCharLookupTable['s'] = ' '
24
+	escapedCharLookupTable['r'] = '\r'
25
+	escapedCharLookupTable['n'] = '\n'
26
+}
27
+
28
+// EscapeTagValue takes a value, and returns an escaped message tag value.
29
+//
30
+// This function is automatically used when lines are created from an
31
+// IrcMessage, so you don't need to call it yourself before creating a line.
32
+func EscapeTagValue(inString string) string {
33
+	return valtoescape.Replace(inString)
34
+}
35
+
36
+// UnescapeTagValue takes an escaped message tag value, and returns the raw value.
37
+//
38
+// This function is automatically used when lines are interpreted by ParseLine,
39
+// so you don't need to call it yourself after parsing a line.
40
+func UnescapeTagValue(inString string) string {
41
+	// buf.Len() == 0 is the fastpath where we have not needed to unescape any chars
42
+	var buf bytes.Buffer
43
+	remainder := inString
44
+	for {
45
+		backslashPos := strings.IndexByte(remainder, '\\')
46
+
47
+		if backslashPos == -1 {
48
+			if buf.Len() == 0 {
49
+				return inString
50
+			} else {
51
+				buf.WriteString(remainder)
52
+				break
53
+			}
54
+		} else if backslashPos == len(remainder)-1 {
55
+			// trailing backslash, which we strip
56
+			if buf.Len() == 0 {
57
+				return inString[:len(inString)-1]
58
+			} else {
59
+				buf.WriteString(remainder[:len(remainder)-1])
60
+				break
61
+			}
62
+		}
63
+
64
+		// non-trailing backslash detected; we're now on the slowpath
65
+		// where we modify the string
66
+		if buf.Len() == 0 {
67
+			buf.Grow(len(inString)) // just an optimization
68
+		}
69
+		buf.WriteString(remainder[:backslashPos])
70
+		buf.WriteByte(escapedCharLookupTable[remainder[backslashPos+1]])
71
+		remainder = remainder[backslashPos+2:]
72
+	}
73
+
74
+	return buf.String()
75
+}

+ 9
- 0
vendor/github.com/mattn/go-colorable/.travis.yml View File

@@ -0,0 +1,9 @@
1
+language: go
2
+go:
3
+  - tip
4
+
5
+before_install:
6
+  - go get github.com/mattn/goveralls
7
+  - go get golang.org/x/tools/cmd/cover
8
+script:
9
+  - $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw

+ 21
- 0
vendor/github.com/mattn/go-colorable/LICENSE View File

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

+ 48
- 0
vendor/github.com/mattn/go-colorable/README.md View File

@@ -0,0 +1,48 @@
1
+# go-colorable
2
+
3
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
4
+[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
5
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
6
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
7
+
8
+Colorable writer for windows.
9
+
10
+For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
11
+This package is possible to handle escape sequence for ansi color on windows.
12
+
13
+## Too Bad!
14
+
15
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
16
+
17
+
18
+## So Good!
19
+
20
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
21
+
22
+## Usage
23
+
24
+```go
25
+logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
26
+logrus.SetOutput(colorable.NewColorableStdout())
27
+
28
+logrus.Info("succeeded")
29
+logrus.Warn("not correct")
30
+logrus.Error("something error")
31
+logrus.Fatal("panic")
32
+```
33
+
34
+You can compile above code on non-windows OSs.
35
+
36
+## Installation
37
+
38
+```
39
+$ go get github.com/mattn/go-colorable
40
+```
41
+
42
+# License
43
+
44
+MIT
45
+
46
+# Author
47
+
48
+Yasuhiro Matsumoto (a.k.a mattn)

+ 29
- 0
vendor/github.com/mattn/go-colorable/colorable_appengine.go View File

@@ -0,0 +1,29 @@
1
+// +build appengine
2
+
3
+package colorable
4
+
5
+import (
6
+	"io"
7
+	"os"
8
+
9
+	_ "github.com/mattn/go-isatty"
10
+)
11
+
12
+// NewColorable returns new instance of Writer which handles escape sequence.
13
+func NewColorable(file *os.File) io.Writer {
14
+	if file == nil {
15
+		panic("nil passed instead of *os.File to NewColorable()")
16
+	}
17
+
18
+	return file
19
+}
20
+
21
+// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
22
+func NewColorableStdout() io.Writer {
23
+	return os.Stdout
24
+}
25
+
26
+// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
27
+func NewColorableStderr() io.Writer {
28
+	return os.Stderr
29
+}

+ 30
- 0
vendor/github.com/mattn/go-colorable/colorable_others.go View File

@@ -0,0 +1,30 @@
1
+// +build !windows
2
+// +build !appengine
3
+
4
+package colorable
5
+
6
+import (
7
+	"io"
8
+	"os"
9
+
10
+	_ "github.com/mattn/go-isatty"
11
+)
12
+
13
+// NewColorable returns new instance of Writer which handles escape sequence.
14
+func NewColorable(file *os.File) io.Writer {
15
+	if file == nil {
16
+		panic("nil passed instead of *os.File to NewColorable()")
17
+	}
18
+
19
+	return file
20
+}
21
+
22
+// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
23
+func NewColorableStdout() io.Writer {
24
+	return os.Stdout
25
+}
26
+
27
+// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
28
+func NewColorableStderr() io.Writer {
29
+	return os.Stderr
30
+}

+ 1005
- 0
vendor/github.com/mattn/go-colorable/colorable_windows.go
File diff suppressed because it is too large
View File


+ 3
- 0
vendor/github.com/mattn/go-colorable/go.mod View File

@@ -0,0 +1,3 @@
1
+module github.com/mattn/go-colorable
2
+
3
+require github.com/mattn/go-isatty v0.0.8

+ 4
- 0
vendor/github.com/mattn/go-colorable/go.sum View File

@@ -0,0 +1,4 @@
1
+github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
2
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
3
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
4
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

+ 55
- 0
vendor/github.com/mattn/go-colorable/noncolorable.go View File

@@ -0,0 +1,55 @@
1
+package colorable
2
+
3
+import (
4
+	"bytes"
5
+	"io"
6
+)
7
+
8
+// NonColorable holds writer but removes escape sequence.
9
+type NonColorable struct {
10
+	out io.Writer
11
+}
12
+
13
+// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
14
+func NewNonColorable(w io.Writer) io.Writer {
15
+	return &NonColorable{out: w}
16
+}
17
+
18
+// Write writes data on console
19
+func (w *NonColorable) Write(data []byte) (n int, err error) {
20
+	er := bytes.NewReader(data)
21
+	var bw [1]byte
22
+loop:
23
+	for {
24
+		c1, err := er.ReadByte()
25
+		if err != nil {
26
+			break loop
27
+		}
28
+		if c1 != 0x1b {
29
+			bw[0] = c1
30
+			w.out.Write(bw[:])
31
+			continue
32
+		}
33
+		c2, err := er.ReadByte()
34
+		if err != nil {
35
+			break loop
36
+		}
37
+		if c2 != 0x5b {
38
+			continue
39
+		}
40
+
41
+		var buf bytes.Buffer
42
+		for {
43
+			c, err := er.ReadByte()
44
+			if err != nil {
45
+				break loop
46
+			}
47
+			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
48
+				break
49
+			}
50
+			buf.Write([]byte(string(c)))
51
+		}
52
+	}
53
+
54
+	return len(data), nil
55
+}

+ 13
- 0
vendor/github.com/mattn/go-isatty/.travis.yml View File

@@ -0,0 +1,13 @@
1
+language: go
2
+go:
3
+  - tip
4
+
5
+os:
6
+  - linux
7
+  - osx
8
+
9
+before_install:
10
+  - go get github.com/mattn/goveralls
11
+  - go get golang.org/x/tools/cmd/cover
12
+script:
13
+  - $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5

+ 9
- 0
vendor/github.com/mattn/go-isatty/LICENSE View File

@@ -0,0 +1,9 @@
1
+Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
2
+
3
+MIT License (Expat)
4
+
5
+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:
6
+
7
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+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.

+ 50
- 0
vendor/github.com/mattn/go-isatty/README.md View File

@@ -0,0 +1,50 @@
1
+# go-isatty
2
+
3
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
4
+[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
5
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
6
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
7
+
8
+isatty for golang
9
+
10
+## Usage
11
+
12
+```go
13
+package main
14
+
15
+import (
16
+	"fmt"
17
+	"github.com/mattn/go-isatty"
18
+	"os"
19
+)
20
+
21
+func main() {
22
+	if isatty.IsTerminal(os.Stdout.Fd()) {
23
+		fmt.Println("Is Terminal")
24
+	} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
25
+		fmt.Println("Is Cygwin/MSYS2 Terminal")
26
+	} else {
27
+		fmt.Println("Is Not Terminal")
28
+	}
29
+}
30
+```
31
+
32
+## Installation
33
+
34
+```
35
+$ go get github.com/mattn/go-isatty
36
+```
37
+
38
+## License
39
+
40
+MIT
41
+
42
+## Author
43
+
44
+Yasuhiro Matsumoto (a.k.a mattn)
45
+
46
+## Thanks
47
+
48
+* k-takata: base idea for IsCygwinTerminal
49
+
50
+    https://github.com/k-takata/go-iscygpty

+ 2
- 0
vendor/github.com/mattn/go-isatty/doc.go View File

@@ -0,0 +1,2 @@
1
+// Package isatty implements interface to isatty
2
+package isatty

+ 5
- 0
vendor/github.com/mattn/go-isatty/go.mod View File

@@ -0,0 +1,5 @@
1
+module github.com/mattn/go-isatty
2
+
3
+require golang.org/x/sys v0.0.0-20191008105621-543471e840be
4
+
5
+go 1.14

+ 4
- 0
vendor/github.com/mattn/go-isatty/go.sum View File

@@ -0,0 +1,4 @@
1
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
2
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
3
+golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
4
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

+ 23
- 0
vendor/github.com/mattn/go-isatty/isatty_android.go View File

@@ -0,0 +1,23 @@
1
+// +build android
2
+
3
+package isatty
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+const ioctlReadTermios = syscall.TCGETS
11
+
12
+// IsTerminal return true if the file descriptor is terminal.
13
+func IsTerminal(fd uintptr) bool {
14
+	var termios syscall.Termios
15
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
16
+	return err == 0
17
+}
18
+
19
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
20
+// terminal. This is also always false on this environment.
21
+func IsCygwinTerminal(fd uintptr) bool {
22
+	return false
23
+}

+ 24
- 0
vendor/github.com/mattn/go-isatty/isatty_bsd.go View File

@@ -0,0 +1,24 @@
1
+// +build darwin freebsd openbsd netbsd dragonfly
2
+// +build !appengine
3
+
4
+package isatty
5
+
6
+import (
7
+	"syscall"
8
+	"unsafe"
9
+)
10
+
11
+const ioctlReadTermios = syscall.TIOCGETA
12
+
13
+// IsTerminal return true if the file descriptor is terminal.
14
+func IsTerminal(fd uintptr) bool {
15
+	var termios syscall.Termios
16
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
17
+	return err == 0
18
+}
19
+
20
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
21
+// terminal. This is also always false on this environment.
22
+func IsCygwinTerminal(fd uintptr) bool {
23
+	return false
24
+}

+ 15
- 0
vendor/github.com/mattn/go-isatty/isatty_others.go View File

@@ -0,0 +1,15 @@
1
+// +build appengine js nacl
2
+
3
+package isatty
4
+
5
+// IsTerminal returns true if the file descriptor is terminal which
6
+// is always false on js and appengine classic which is a sandboxed PaaS.
7
+func IsTerminal(fd uintptr) bool {
8
+	return false
9
+}
10
+
11
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
12
+// terminal. This is also always false on this environment.
13
+func IsCygwinTerminal(fd uintptr) bool {
14
+	return false
15
+}

+ 22
- 0
vendor/github.com/mattn/go-isatty/isatty_plan9.go View File

@@ -0,0 +1,22 @@
1
+// +build plan9
2
+
3
+package isatty
4
+
5
+import (
6
+	"syscall"
7
+)
8
+
9
+// IsTerminal returns true if the given file descriptor is a terminal.
10
+func IsTerminal(fd uintptr) bool {
11
+	path, err := syscall.Fd2path(fd)
12
+	if err != nil {
13
+		return false
14
+	}
15
+	return path == "/dev/cons" || path == "/mnt/term/dev/cons"
16
+}
17
+
18
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
19
+// terminal. This is also always false on this environment.
20
+func IsCygwinTerminal(fd uintptr) bool {
21
+	return false
22
+}

+ 22
- 0
vendor/github.com/mattn/go-isatty/isatty_solaris.go View File

@@ -0,0 +1,22 @@
1
+// +build solaris
2
+// +build !appengine
3
+
4
+package isatty
5
+
6
+import (
7
+	"golang.org/x/sys/unix"
8
+)
9
+
10
+// IsTerminal returns true if the given file descriptor is a terminal.
11
+// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
12
+func IsTerminal(fd uintptr) bool {
13
+	var termio unix.Termio
14
+	err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
15
+	return err == nil
16
+}
17
+
18
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
19
+// terminal. This is also always false on this environment.
20
+func IsCygwinTerminal(fd uintptr) bool {
21
+	return false
22
+}

+ 19
- 0
vendor/github.com/mattn/go-isatty/isatty_tcgets.go View File

@@ -0,0 +1,19 @@
1
+// +build linux aix
2
+// +build !appengine
3
+// +build !android
4
+
5
+package isatty
6
+
7
+import "golang.org/x/sys/unix"
8
+
9
+// IsTerminal return true if the file descriptor is terminal.
10
+func IsTerminal(fd uintptr) bool {
11
+	_, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
12
+	return err == nil
13
+}
14
+
15
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
16
+// terminal. This is also always false on this environment.
17
+func IsCygwinTerminal(fd uintptr) bool {
18
+	return false
19
+}

+ 125
- 0
vendor/github.com/mattn/go-isatty/isatty_windows.go View File

@@ -0,0 +1,125 @@
1
+// +build windows
2
+// +build !appengine
3
+
4
+package isatty
5
+
6
+import (
7
+	"errors"
8
+	"strings"
9
+	"syscall"
10
+	"unicode/utf16"
11
+	"unsafe"
12
+)
13
+
14
+const (
15
+	objectNameInfo uintptr = 1
16
+	fileNameInfo           = 2
17
+	fileTypePipe           = 3
18
+)
19
+
20
+var (
21
+	kernel32                         = syscall.NewLazyDLL("kernel32.dll")
22
+	ntdll                            = syscall.NewLazyDLL("ntdll.dll")
23
+	procGetConsoleMode               = kernel32.NewProc("GetConsoleMode")
24
+	procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
25
+	procGetFileType                  = kernel32.NewProc("GetFileType")
26
+	procNtQueryObject                = ntdll.NewProc("NtQueryObject")
27
+)
28
+
29
+func init() {
30
+	// Check if GetFileInformationByHandleEx is available.
31
+	if procGetFileInformationByHandleEx.Find() != nil {
32
+		procGetFileInformationByHandleEx = nil
33
+	}
34
+}
35
+
36
+// IsTerminal return true if the file descriptor is terminal.
37
+func IsTerminal(fd uintptr) bool {
38
+	var st uint32
39
+	r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
40
+	return r != 0 && e == 0
41
+}
42
+
43
+// Check pipe name is used for cygwin/msys2 pty.
44
+// Cygwin/MSYS2 PTY has a name like:
45
+//   \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
46
+func isCygwinPipeName(name string) bool {
47
+	token := strings.Split(name, "-")
48
+	if len(token) < 5 {
49
+		return false
50
+	}
51
+
52
+	if token[0] != `\msys` &&
53
+		token[0] != `\cygwin` &&
54
+		token[0] != `\Device\NamedPipe\msys` &&
55
+		token[0] != `\Device\NamedPipe\cygwin` {
56
+		return false
57
+	}
58
+
59
+	if token[1] == "" {
60
+		return false
61
+	}
62
+
63
+	if !strings.HasPrefix(token[2], "pty") {
64
+		return false
65
+	}
66
+
67
+	if token[3] != `from` && token[3] != `to` {
68
+		return false
69
+	}
70
+
71
+	if token[4] != "master" {
72
+		return false
73
+	}
74
+
75
+	return true
76
+}
77
+
78
+// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
79
+// since GetFileInformationByHandleEx is not avilable under windows Vista and still some old fashion
80
+// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
81
+// Windows vista to 10
82
+// see https://stackoverflow.com/a/18792477 for details
83
+func getFileNameByHandle(fd uintptr) (string, error) {
84
+	if procNtQueryObject == nil {
85
+		return "", errors.New("ntdll.dll: NtQueryObject not supported")
86
+	}
87
+
88
+	var buf [4 + syscall.MAX_PATH]uint16
89
+	var result int
90
+	r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
91
+		fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
92
+	if r != 0 {
93
+		return "", e
94
+	}
95
+	return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
96
+}
97
+
98
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
99
+// terminal.
100
+func IsCygwinTerminal(fd uintptr) bool {
101
+	if procGetFileInformationByHandleEx == nil {
102
+		name, err := getFileNameByHandle(fd)
103
+		if err != nil {
104
+			return false
105
+		}
106
+		return isCygwinPipeName(name)
107
+	}
108
+
109
+	// Cygwin/msys's pty is a pipe.
110
+	ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
111
+	if ft != fileTypePipe || e != 0 {
112
+		return false
113
+	}
114
+
115
+	var buf [2 + syscall.MAX_PATH]uint16
116
+	r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
117
+		4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
118
+		uintptr(len(buf)*2), 0, 0)
119
+	if r == 0 || e != 0 {
120
+		return false
121
+	}
122
+
123
+	l := *(*uint32)(unsafe.Pointer(&buf))
124
+	return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
125
+}

+ 1
- 0
vendor/github.com/mgutz/ansi/.gitignore View File

@@ -0,0 +1 @@
1
+*.test

+ 9
- 0
vendor/github.com/mgutz/ansi/LICENSE View File

@@ -0,0 +1,9 @@
1
+The MIT License (MIT)
2
+Copyright (c) 2013 Mario L. Gutierrez
3
+
4
+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:
5
+
6
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+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.
9
+

+ 121
- 0
vendor/github.com/mgutz/ansi/README.md View File

@@ -0,0 +1,121 @@
1
+# ansi
2
+
3
+Package ansi is a small, fast library to create ANSI colored strings and codes.
4
+
5
+## Install
6
+
7
+Get it
8
+
9
+```sh
10
+go get -u github.com/mgutz/ansi
11
+```
12
+
13
+## Example
14
+
15
+```go
16
+import "github.com/mgutz/ansi"
17
+
18
+// colorize a string, SLOW
19
+msg := ansi.Color("foo", "red+b:white")
20
+
21
+// create a FAST closure function to avoid computation of ANSI code
22
+phosphorize := ansi.ColorFunc("green+h:black")
23
+msg = phosphorize("Bring back the 80s!")
24
+msg2 := phospohorize("Look, I'm a CRT!")
25
+
26
+// cache escape codes and build strings manually
27
+lime := ansi.ColorCode("green+h:black")
28
+reset := ansi.ColorCode("reset")
29
+
30
+fmt.Println(lime, "Bring back the 80s!", reset)
31
+```
32
+
33
+Other examples
34
+
35
+```go
36
+Color(s, "red")            // red
37
+Color(s, "red+b")          // red bold
38
+Color(s, "red+B")          // red blinking
39
+Color(s, "red+u")          // red underline
40
+Color(s, "red+bh")         // red bold bright
41
+Color(s, "red:white")      // red on white
42
+Color(s, "red+b:white+h")  // red bold on white bright
43
+Color(s, "red+B:white+h")  // red blink on white bright
44
+Color(s, "off")            // turn off ansi codes
45
+```
46
+
47
+To view color combinations, from project directory in terminal.
48
+
49
+```sh
50
+go test
51
+```
52
+
53
+## Style format
54
+
55
+```go
56
+"foregroundColor+attributes:backgroundColor+attributes"
57
+```
58
+
59
+Colors
60
+
61
+* black
62
+* red
63
+* green
64
+* yellow
65
+* blue
66
+* magenta
67
+* cyan
68
+* white
69
+* 0...255 (256 colors)
70
+
71
+Foreground Attributes
72
+
73
+* B = Blink
74
+* b = bold
75
+* h = high intensity (bright)
76
+* i = inverse
77
+* s = strikethrough
78
+* u = underline
79
+
80
+Background Attributes
81
+
82
+* h = high intensity (bright)
83
+
84
+## Constants
85
+
86
+* ansi.Reset
87
+* ansi.DefaultBG
88
+* ansi.DefaultFG
89
+* ansi.Black
90
+* ansi.Red
91
+* ansi.Green
92
+* ansi.Yellow
93
+* ansi.Blue
94
+* ansi.Magenta
95
+* ansi.Cyan
96
+* ansi.White
97
+* ansi.LightBlack
98
+* ansi.LightRed
99
+* ansi.LightGreen
100
+* ansi.LightYellow
101
+* ansi.LightBlue
102
+* ansi.LightMagenta
103
+* ansi.LightCyan
104
+* ansi.LightWhite
105
+
106
+## References
107
+
108
+Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
109
+
110
+General [tips and formatting](http://misc.flogisoft.com/bash/tip_colors_and_formatting)
111
+
112
+What about support on Windows? Use [colorable by mattn](https://github.com/mattn/go-colorable).
113
+Ansi and colorable are used by [logxi](https://github.com/mgutz/logxi) to support logging in
114
+color on Windows.
115
+
116
+## MIT License
117
+
118
+Copyright (c) 2013 Mario Gutierrez mario@mgutz.com
119
+
120
+See the file LICENSE for copying permission.
121
+

+ 285
- 0
vendor/github.com/mgutz/ansi/ansi.go View File

@@ -0,0 +1,285 @@
1
+package ansi
2
+
3
+import (
4
+	"bytes"
5
+	"fmt"
6
+	"strconv"
7
+	"strings"
8
+)
9
+
10
+const (
11
+	black = iota
12
+	red
13
+	green
14
+	yellow
15
+	blue
16
+	magenta
17
+	cyan
18
+	white
19
+	defaultt = 9
20
+
21
+	normalIntensityFG = 30
22
+	highIntensityFG   = 90
23
+	normalIntensityBG = 40
24
+	highIntensityBG   = 100
25
+
26
+	start         = "\033["
27
+	bold          = "1;"
28
+	blink         = "5;"
29
+	underline     = "4;"
30
+	inverse       = "7;"
31
+	strikethrough = "9;"
32
+
33
+	// Reset is the ANSI reset escape sequence
34
+	Reset = "\033[0m"
35
+	// DefaultBG is the default background
36
+	DefaultBG = "\033[49m"
37
+	// DefaultFG is the default foreground
38
+	DefaultFG = "\033[39m"
39
+)
40
+
41
+// Black FG
42
+var Black string
43
+
44
+// Red FG
45
+var Red string
46
+
47
+// Green FG
48
+var Green string
49
+
50
+// Yellow FG
51
+var Yellow string
52
+
53
+// Blue FG
54
+var Blue string
55
+
56
+// Magenta FG
57
+var Magenta string
58
+
59
+// Cyan FG
60
+var Cyan string
61
+
62
+// White FG
63
+var White string
64
+
65
+// LightBlack FG
66
+var LightBlack string
67
+
68
+// LightRed FG
69
+var LightRed string
70
+
71
+// LightGreen FG
72
+var LightGreen string
73
+
74
+// LightYellow FG
75
+var LightYellow string
76
+
77
+// LightBlue FG
78
+var LightBlue string
79
+
80
+// LightMagenta FG
81
+var LightMagenta string
82
+
83
+// LightCyan FG
84
+var LightCyan string
85
+
86
+// LightWhite FG
87
+var LightWhite string
88
+
89
+var (
90
+	plain = false
91
+	// Colors maps common color names to their ANSI color code.
92
+	Colors = map[string]int{
93
+		"black":   black,
94
+		"red":     red,
95
+		"green":   green,
96
+		"yellow":  yellow,
97
+		"blue":    blue,
98
+		"magenta": magenta,
99
+		"cyan":    cyan,
100
+		"white":   white,
101
+		"default": defaultt,
102
+	}
103
+)
104
+
105
+func init() {
106
+	for i := 0; i < 256; i++ {
107
+		Colors[strconv.Itoa(i)] = i
108
+	}
109
+
110
+	Black = ColorCode("black")
111
+	Red = ColorCode("red")
112
+	Green = ColorCode("green")
113
+	Yellow = ColorCode("yellow")
114
+	Blue = ColorCode("blue")
115
+	Magenta = ColorCode("magenta")
116
+	Cyan = ColorCode("cyan")
117
+	White = ColorCode("white")
118
+	LightBlack = ColorCode("black+h")
119
+	LightRed = ColorCode("red+h")
120
+	LightGreen = ColorCode("green+h")
121
+	LightYellow = ColorCode("yellow+h")
122
+	LightBlue = ColorCode("blue+h")
123
+	LightMagenta = ColorCode("magenta+h")
124
+	LightCyan = ColorCode("cyan+h")
125
+	LightWhite = ColorCode("white+h")
126
+}
127
+
128
+// ColorCode returns the ANSI color color code for style.
129
+func ColorCode(style string) string {
130
+	return colorCode(style).String()
131
+}
132
+
133
+// Gets the ANSI color code for a style.
134
+func colorCode(style string) *bytes.Buffer {
135
+	buf := bytes.NewBufferString("")
136
+	if plain || style == "" {
137
+		return buf
138
+	}
139
+	if style == "reset" {
140
+		buf.WriteString(Reset)
141
+		return buf
142
+	} else if style == "off" {
143
+		return buf
144
+	}
145
+
146
+	foregroundBackground := strings.Split(style, ":")
147
+	foreground := strings.Split(foregroundBackground[0], "+")
148
+	fgKey := foreground[0]
149
+	fg := Colors[fgKey]
150
+	fgStyle := ""
151
+	if len(foreground) > 1 {
152
+		fgStyle = foreground[1]
153
+	}
154
+
155
+	bg, bgStyle := "", ""
156
+
157
+	if len(foregroundBackground) > 1 {
158
+		background := strings.Split(foregroundBackground[1], "+")
159
+		bg = background[0]
160
+		if len(background) > 1 {
161
+			bgStyle = background[1]
162
+		}
163
+	}
164
+
165
+	buf.WriteString(start)
166
+	base := normalIntensityFG
167
+	if len(fgStyle) > 0 {
168
+		if strings.Contains(fgStyle, "b") {
169
+			buf.WriteString(bold)
170
+		}
171
+		if strings.Contains(fgStyle, "B") {
172
+			buf.WriteString(blink)
173
+		}
174
+		if strings.Contains(fgStyle, "u") {
175
+			buf.WriteString(underline)
176
+		}
177
+		if strings.Contains(fgStyle, "i") {
178
+			buf.WriteString(inverse)
179
+		}
180
+		if strings.Contains(fgStyle, "s") {
181
+			buf.WriteString(strikethrough)
182
+		}
183
+		if strings.Contains(fgStyle, "h") {
184
+			base = highIntensityFG
185
+		}
186
+	}
187
+
188
+	// if 256-color
189
+	n, err := strconv.Atoi(fgKey)
190
+	if err == nil {
191
+		fmt.Fprintf(buf, "38;5;%d;", n)
192
+	} else {
193
+		fmt.Fprintf(buf, "%d;", base+fg)
194
+	}
195
+
196
+	base = normalIntensityBG
197
+	if len(bg) > 0 {
198
+		if strings.Contains(bgStyle, "h") {
199
+			base = highIntensityBG
200
+		}
201
+		// if 256-color
202
+		n, err := strconv.Atoi(bg)
203
+		if err == nil {
204
+			fmt.Fprintf(buf, "48;5;%d;", n)
205
+		} else {
206
+			fmt.Fprintf(buf, "%d;", base+Colors[bg])
207
+		}
208
+	}
209
+
210
+	// remove last ";"
211
+	buf.Truncate(buf.Len() - 1)
212
+	buf.WriteRune('m')
213
+	return buf
214
+}
215
+
216
+// Color colors a string based on the ANSI color code for style.
217
+func Color(s, style string) string {
218
+	if plain || len(style) < 1 {
219
+		return s
220
+	}
221
+	buf := colorCode(style)
222
+	buf.WriteString(s)
223
+	buf.WriteString(Reset)
224
+	return buf.String()
225
+}
226
+
227
+// ColorFunc creates a closure to avoid computation ANSI color code.
228
+func ColorFunc(style string) func(string) string {
229
+	if style == "" {
230
+		return func(s string) string {
231
+			return s
232
+		}
233
+	}
234
+	color := ColorCode(style)
235
+	return func(s string) string {
236
+		if plain || s == "" {
237
+			return s
238
+		}
239
+		buf := bytes.NewBufferString(color)
240
+		buf.WriteString(s)
241
+		buf.WriteString(Reset)
242
+		result := buf.String()
243
+		return result
244
+	}
245
+}
246
+
247
+// DisableColors disables ANSI color codes. The default is false (colors are on).
248
+func DisableColors(disable bool) {
249
+	plain = disable
250
+	if plain {
251
+		Black = ""
252
+		Red = ""
253
+		Green = ""
254
+		Yellow = ""
255
+		Blue = ""
256
+		Magenta = ""
257
+		Cyan = ""
258
+		White = ""
259
+		LightBlack = ""
260
+		LightRed = ""
261
+		LightGreen = ""
262
+		LightYellow = ""
263
+		LightBlue = ""
264
+		LightMagenta = ""
265
+		LightCyan = ""
266
+		LightWhite = ""
267
+	} else {
268
+		Black = ColorCode("black")
269
+		Red = ColorCode("red")
270
+		Green = ColorCode("green")
271
+		Yellow = ColorCode("yellow")
272
+		Blue = ColorCode("blue")
273
+		Magenta = ColorCode("magenta")
274
+		Cyan = ColorCode("cyan")
275
+		White = ColorCode("white")
276
+		LightBlack = ColorCode("black+h")
277
+		LightRed = ColorCode("red+h")
278
+		LightGreen = ColorCode("green+h")
279
+		LightYellow = ColorCode("yellow+h")
280
+		LightBlue = ColorCode("blue+h")
281
+		LightMagenta = ColorCode("magenta+h")
282
+		LightCyan = ColorCode("cyan+h")
283
+		LightWhite = ColorCode("white+h")
284
+	}
285
+}

+ 65
- 0
vendor/github.com/mgutz/ansi/doc.go View File

@@ -0,0 +1,65 @@
1
+/*
2
+Package ansi is a small, fast library to create ANSI colored strings and codes.
3
+
4
+Installation
5
+
6
+    # this installs the color viewer and the package
7
+    go get -u github.com/mgutz/ansi/cmd/ansi-mgutz
8
+
9
+Example
10
+
11
+	// colorize a string, SLOW
12
+	msg := ansi.Color("foo", "red+b:white")
13
+
14
+	// create a closure to avoid recalculating ANSI code compilation
15
+	phosphorize := ansi.ColorFunc("green+h:black")
16
+	msg = phosphorize("Bring back the 80s!")
17
+	msg2 := phospohorize("Look, I'm a CRT!")
18
+
19
+	// cache escape codes and build strings manually
20
+	lime := ansi.ColorCode("green+h:black")
21
+	reset := ansi.ColorCode("reset")
22
+
23
+	fmt.Println(lime, "Bring back the 80s!", reset)
24
+
25
+Other examples
26
+
27
+	Color(s, "red")            // red
28
+	Color(s, "red+b")          // red bold
29
+	Color(s, "red+B")          // red blinking
30
+	Color(s, "red+u")          // red underline
31
+	Color(s, "red+bh")         // red bold bright
32
+	Color(s, "red:white")      // red on white
33
+	Color(s, "red+b:white+h")  // red bold on white bright
34
+	Color(s, "red+B:white+h")  // red blink on white bright
35
+
36
+To view color combinations, from terminal
37
+
38
+	ansi-mgutz
39
+
40
+Style format
41
+
42
+	"foregroundColor+attributes:backgroundColor+attributes"
43
+
44
+Colors
45
+
46
+	black
47
+	red
48
+	green
49
+	yellow
50
+	blue
51
+	magenta
52
+	cyan
53
+	white
54
+
55
+Attributes
56
+
57
+	b = bold foreground
58
+	B = Blink foreground
59
+	u = underline foreground
60
+	h = high intensity (bright) foreground, background
61
+	i = inverse
62
+
63
+Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
64
+*/
65
+package ansi

+ 57
- 0
vendor/github.com/mgutz/ansi/print.go View File

@@ -0,0 +1,57 @@
1
+package ansi
2
+
3
+import (
4
+	"fmt"
5
+	"sort"
6
+
7
+	colorable "github.com/mattn/go-colorable"
8
+)
9
+
10
+// PrintStyles prints all style combinations to the terminal.
11
+func PrintStyles() {
12
+	// for compatibility with Windows, not needed for *nix
13
+	stdout := colorable.NewColorableStdout()
14
+
15
+	bgColors := []string{
16
+		"",
17
+		":black",
18
+		":red",
19
+		":green",
20
+		":yellow",
21
+		":blue",
22
+		":magenta",
23
+		":cyan",
24
+		":white",
25
+	}
26
+
27
+	keys := make([]string, 0, len(Colors))
28
+	for k := range Colors {
29
+		keys = append(keys, k)
30
+	}
31
+
32
+	sort.Sort(sort.StringSlice(keys))
33
+
34
+	for _, fg := range keys {
35
+		for _, bg := range bgColors {
36
+			fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
37
+			fmt.Fprintln(stdout, padColor(fg, []string{"+s" + bg, "+i" + bg}))
38
+			fmt.Fprintln(stdout, padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h"}))
39
+			fmt.Fprintln(stdout, padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
40
+		}
41
+	}
42
+}
43
+
44
+func pad(s string, length int) string {
45
+	for len(s) < length {
46
+		s += " "
47
+	}
48
+	return s
49
+}
50
+
51
+func padColor(color string, styles []string) string {
52
+	buffer := ""
53
+	for _, style := range styles {
54
+		buffer += Color(pad(color+style, 20), color+style)
55
+	}
56
+	return buffer
57
+}

+ 2
- 0
vendor/github.com/oragono/confusables/.gitignore View File

@@ -0,0 +1,2 @@
1
+/maketables
2
+confusables.txt

+ 28
- 0
vendor/github.com/oragono/confusables/LICENSE View File

@@ -0,0 +1,28 @@
1
+Copyright (c) 2013 Michael Tibben. All rights reserved.
2
+Copyright (c) 2014 Filippo Valsorda. All rights reserved.
3
+
4
+Redistribution and use in source and binary forms, with or without
5
+modification, are permitted provided that the following conditions are
6
+met:
7
+
8
+   * Redistributions of source code must retain the above copyright
9
+notice, this list of conditions and the following disclaimer.
10
+   * Redistributions in binary form must reproduce the above
11
+copyright notice, this list of conditions and the following disclaimer
12
+in the documentation and/or other materials provided with the
13
+distribution.
14
+   * Neither the name of Google Inc. nor the names of its
15
+contributors may be used to endorse or promote products derived from
16
+this software without specific prior written permission.
17
+
18
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 17
- 0
vendor/github.com/oragono/confusables/README.md View File

@@ -0,0 +1,17 @@
1
+# Unicode confusables
2
+
3
+This Go library implements the `Skeleton` algorithm from Unicode TR39
4
+
5
+See http://www.unicode.org/reports/tr39/
6
+
7
+### Examples
8
+```
9
+import "github.com/mtibben/confusables"
10
+
11
+confusables.Skeleton("𝔭𝒶ỿ𝕡𝕒ℓ")  # "paypal"
12
+confusables.Confusable("𝔭𝒶ỿ𝕡𝕒ℓ", "paypal")  # true
13
+```
14
+
15
+*Note on the use of `Skeleton`, from TR39:*
16
+
17
+> A skeleton is intended only for internal use for testing confusability of strings; the resulting text is not suitable for display to users, because it will appear to be a hodgepodge of different scripts. In particular, the result of mapping an identifier will not necessary be an identifier. Thus the confusability mappings can be used to test whether two identifiers are confusable (if their skeletons are the same), but should definitely not be used as a "normalization" of identifiers.

+ 82
- 0
vendor/github.com/oragono/confusables/confusables.go View File

@@ -0,0 +1,82 @@
1
+//go:generate go run maketables.go > tables.go
2
+
3
+package confusables
4
+
5
+import (
6
+	"bytes"
7
+
8
+	"golang.org/x/text/unicode/norm"
9
+)
10
+
11
+// TODO: document casefolding approaches
12
+// (suggest to force casefold strings; explain how to catch paypal - pAypal)
13
+// TODO: DOC you might want to store the Skeleton and check against it later
14
+// TODO: implement xidmodifications.txt restricted characters
15
+
16
+type lookupFunc func(rune) (string)
17
+
18
+func lookupReplacement(r rune) string {
19
+	return confusablesMap[r]
20
+}
21
+
22
+func lookupReplacementTweaked(r rune) string {
23
+	if replacement, ok := tweaksMap[r]; ok {
24
+		return replacement
25
+	}
26
+	return confusablesMap[r]
27
+}
28
+
29
+func skeletonBase(s string, lookup lookupFunc) string {
30
+
31
+	// 1. Converting X to NFD format
32
+	s = norm.NFD.String(s)
33
+
34
+	// 2. Successively mapping each source character in X to the target string
35
+	// according to the specified data table
36
+	var buf bytes.Buffer
37
+	changed := false // fast path: if this remains false, keep s intact
38
+	prevPos := 0
39
+	var replacement string
40
+	for i, r := range s {
41
+		if changed && replacement == "" {
42
+			buf.WriteString(s[prevPos:i])
43
+		}
44
+		prevPos = i
45
+		replacement = lookup(r)
46
+		if replacement != "" {
47
+			if !changed {
48
+				changed = true
49
+				// first replacement: copy over the previously unmodified text
50
+				buf.WriteString(s[:i])
51
+			}
52
+			buf.WriteString(replacement)
53
+		}
54
+	}
55
+	if changed && replacement == "" {
56
+		buf.WriteString(s[prevPos:]) // loop-and-a-half
57
+	}
58
+	if changed {
59
+		s = buf.String()
60
+	}
61
+
62
+	// 3. Reapplying NFD
63
+	s = norm.NFD.String(s)
64
+
65
+	return s
66
+}
67
+
68
+// Skeleton converts a string to its "skeleton" form
69
+// as described in http://www.unicode.org/reports/tr39/#Confusable_Detection
70
+func Skeleton(s string) string {
71
+	return skeletonBase(s, lookupReplacement)
72
+}
73
+
74
+// SkeletonTweaked is like Skeleton, but it implements some custom overrides
75
+// to the confusables table (currently it removes the m -> rn mapping):
76
+func SkeletonTweaked(s string) string {
77
+	return skeletonBase(s, lookupReplacementTweaked)
78
+}
79
+
80
+func Confusable(x, y string) bool {
81
+	return Skeleton(x) == Skeleton(y)
82
+}

+ 6317
- 0
vendor/github.com/oragono/confusables/tables.go
File diff suppressed because it is too large
View File


+ 38
- 0
vendor/github.com/oragono/confusables/tweaks.go View File

@@ -0,0 +1,38 @@
1
+package confusables
2
+
3
+// these are overrides for the standard confusables table:
4
+// a mapping to "" means "don't map", a mapping to a replacement means
5
+// "replace with this", no entry means "defer to the standard table"
6
+
7
+var tweaksMap = map[rune]string{
8
+	// ASCII-to-ASCII mapping that we are removing:
9
+	0x6d: "", // m -> rn
10
+	// these characters are confusable with m, hence the official table
11
+	// maps them to rn (`grep "LATIN SMALL LETTER R, LATIN SMALL LETTER N" confusables.txt`)
12
+	0x118E3: "m", // 118E3 ; 0072 006E ;     MA      # ( 𑣣 → rn ) WARANG CITI DIGIT THREE → LATIN SMALL LETTER R, LATIN SMALL LETTER N
13
+	0x11700: "m", // 11700 ; 0072 006E ;     MA      # ( 𑜀 → rn ) AHOM LETTER KA → LATIN SMALL LETTER R, LATIN SMALL LETTER N
14
+	// the table thinks this is confusable with  m̦ but I think it's confusable with m:
15
+	0x0271:  "m", // 0271 ;	0072 006E 0326 ;	MA	# ( ɱ → rn̦ ) LATIN SMALL LETTER M WITH HOOK → LATIN SMALL LETTER R, LATIN SMALL LETTER N, COMBINING COMMA BELOW	# →m̡→
16
+
17
+	/*
18
+	// ASCII-to-ASCII mapping that we are removing:
19
+	0x49: "", // I -> l
20
+	// these characters are confusable with I, hence the official table
21
+	// maps them to l (`grep "LATIN SMALL LETTER L" confusables.txt`)
22
+	0x0399: "I", // 0399 ;	006C ;	MA	# ( Ι → l ) GREEK CAPITAL LETTER IOTA → LATIN SMALL LETTER L	# 
23
+	0x0406: "I", // 0406 ;	006C ;	MA	# ( І → l ) CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I → LATIN SMALL LETTER L	# 
24
+	0x04C0: "I", // 04C0 ;	006C ;	MA	# ( Ӏ → l ) CYRILLIC LETTER PALOCHKA → LATIN SMALL LETTER L	# 
25
+
26
+	// ASCII-to-ASCII mapping that we are removing:
27
+	0x31: "", // 1 -> l
28
+	// these characters are confusable with 1, hence the official table
29
+	// maps them to l (`grep "LATIN SMALL LETTER L" confusables.txt`)
30
+	// [nothing yet]
31
+
32
+	// ASCII-to-ASCII mapping that we are removing:
33
+	0x30: "", // 0 -> O
34
+	// these characters are confusable with 0, hence the official table
35
+	// maps them to O (`grep "LATIN CAPITAL LETTER O\>" confusables.txt`)
36
+	// [nothing yet]
37
+	*/
38
+}

+ 20
- 0
vendor/github.com/oragono/go-ident/LICENSE View File

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

+ 19
- 0
vendor/github.com/oragono/go-ident/README.md View File

@@ -0,0 +1,19 @@
1
+# RFC 1413 (Identification Protocol) client
2
+
3
+This package provides a client for the [Identification Protocol](https://tools.ietf.org/html/rfc1413).
4
+
5
+---
6
+
7
+[![GoDoc](https://godoc.org/github.com/DanielOaks/go-ident?status.svg)](https://godoc.org/github.com/DanielOaks/go-ident) [![Go Report Card](https://goreportcard.com/badge/github.com/DanielOaks/go-ident)](https://goreportcard.com/report/github.com/DanielOaks/go-ident)
8
+
9
+---
10
+
11
+## Installation
12
+
13
+```sh
14
+go get github.com/DanielOaks/go-ident
15
+```
16
+
17
+## Documentation
18
+
19
+Documentation can be found at [godoc.org](http://godoc.org/github.com/DanielOaks/go-ident).

+ 0
- 0
vendor/github.com/oragono/go-ident/client.go View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save