@@ -2,6 +2,7 @@ package cli
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "strings"
78 "time"
@@ -14,22 +15,33 @@ type App struct {
1415}
1516
1617func NewApp () * App {
17- return & App {inputTimeout : 3 * time .Second }
18+ return & App {
19+ inputTimeout : 3 * time .Second ,
20+ }
1821}
1922
2023func (a * App ) Run () error {
2124 for {
2225 config , err := a .collectConfig ()
2326 if err != nil {
27+ if errors .Is (err , errAborted ) {
28+ return nil
29+ }
2430 return err
2531 }
2632
2733 if err := a .execute (config ); err != nil {
34+ if errors .Is (err , errAborted ) {
35+ return nil
36+ }
2837 return err
2938 }
3039
3140 again , err := a .askAgain ()
3241 if err != nil {
42+ if errors .Is (err , errAborted ) {
43+ return nil
44+ }
3345 return err
3446 }
3547 if ! again {
@@ -39,28 +51,117 @@ func (a *App) Run() error {
3951}
4052
4153type Config struct {
54+ Mode Mode
55+ Direct DirectConfig
56+ Lookup LookupConfig
57+ }
58+
59+ func (a * App ) collectConfig () (Config , error ) {
60+ mode , err := a .askMode ()
61+ if err != nil {
62+ return Config {}, err
63+ }
64+
65+ if mode == ModeLookup {
66+ lookup , err := a .collectLookupConfig ()
67+ if err != nil {
68+ return Config {}, err
69+ }
70+ return Config {Mode : mode , Lookup : lookup }, nil
71+ }
72+
73+ direct , err := a .collectDirectConfig ()
74+ if err != nil {
75+ return Config {}, err
76+ }
77+
78+ return Config {Mode : mode , Direct : direct }, nil
79+ }
80+
81+ type Mode string
82+
83+ const (
84+ ModeDirect Mode = "direct"
85+ ModeLookup Mode = "lookup"
86+ )
87+
88+ type DirectConfig struct {
4289 Host string
4390 Port int
4491 Edition ping.Edition
4592}
4693
47- func (a * App ) collectConfig () (Config , error ) {
94+ type LookupConfig struct {
95+ Edition ping.Edition
96+ BaseHost string
97+ Port int
98+ Subdomains []string
99+ Endings []string
100+ }
101+
102+ func (a * App ) collectDirectConfig () (DirectConfig , error ) {
48103 edition , err := a .askEdition ()
49104 if err != nil {
50- return Config {}, err
105+ return DirectConfig {}, err
51106 }
52107
53108 host , err := a .askHost ()
54109 if err != nil {
55- return Config {}, err
110+ return DirectConfig {}, err
56111 }
57112
58113 port , err := a .askPort (edition )
59114 if err != nil {
60- return Config {}, err
115+ return DirectConfig {}, err
116+ }
117+
118+ return DirectConfig {Host : host , Port : port , Edition : edition }, nil
119+ }
120+
121+ func (a * App ) collectLookupConfig () (LookupConfig , error ) {
122+ edition , err := a .askEdition ()
123+ if err != nil {
124+ return LookupConfig {}, err
125+ }
126+
127+ subdomains , err := a .askSubdomainChoice ()
128+ if err != nil {
129+ return LookupConfig {}, err
130+ }
131+
132+ baseHost , err := a .askBaseHost ()
133+ if err != nil {
134+ return LookupConfig {}, err
135+ }
136+
137+ endings , err := a .askDomainEndings ()
138+ if err != nil {
139+ return LookupConfig {}, err
61140 }
62141
63- return Config {Host : host , Port : port , Edition : edition }, nil
142+ port , err := a .askPort (edition )
143+ if err != nil {
144+ return LookupConfig {}, err
145+ }
146+
147+ return LookupConfig {
148+ Edition : edition ,
149+ BaseHost : baseHost ,
150+ Port : port ,
151+ Subdomains : subdomains ,
152+ Endings : endings ,
153+ }, nil
154+ }
155+
156+ func (a * App ) askMode () (Mode , error ) {
157+ index , err := selectOption ("Startmodus" , []string {"UWP/TCP Abfrage" , "IP Lookup" })
158+ if err != nil {
159+ return "" , err
160+ }
161+ if index == 1 {
162+ return ModeLookup , nil
163+ }
164+ return ModeDirect , nil
64165}
65166
66167func (a * App ) askEdition () (ping.Edition , error ) {
@@ -89,6 +190,69 @@ func (a *App) askHost() (string, error) {
89190 }
90191}
91192
193+ func (a * App ) askBaseHost () (string , error ) {
194+ var errMsg string
195+ for {
196+ value , err := promptInput ("IP/Domain ohne Endung" , "z.B. example" , errMsg )
197+ if err != nil {
198+ return "" , err
199+ }
200+ value = strings .TrimSpace (value )
201+ if value == "" {
202+ errMsg = "Wert darf nicht leer sein"
203+ continue
204+ }
205+ return value , nil
206+ }
207+ }
208+
209+ func (a * App ) askSubdomainChoice () ([]string , error ) {
210+ index , err := selectOption ("Subdomain" , []string {"Eigene Subdomain" , "Subdomain-Pool" })
211+ if err != nil {
212+ return nil , err
213+ }
214+ if index == 1 {
215+ return subdomainPool , nil
216+ }
217+
218+ var errMsg string
219+ for {
220+ value , err := promptInput ("Subdomain (optional)" , "z.B. play (leer lassen für keine)" , errMsg )
221+ if err != nil {
222+ return nil , err
223+ }
224+ value = strings .TrimSpace (value )
225+ return []string {value }, nil
226+ }
227+ }
228+
229+ func (a * App ) askDomainEndings () ([]string , error ) {
230+ index , err := selectOption ("Domain-Endung" , []string {"Eigene Endung" , "Endungs-Pool" })
231+ if err != nil {
232+ return nil , err
233+ }
234+ if index == 1 {
235+ endings , err := loadDomainEndings ()
236+ if err != nil {
237+ return endings , nil
238+ }
239+ return endings , nil
240+ }
241+ var errMsg string
242+ for {
243+ value , err := promptInput ("Domain-Endung" , "z.B. com oder de" , errMsg )
244+ if err != nil {
245+ return nil , err
246+ }
247+ value = normalizeEnding (value )
248+ if value == "" {
249+ errMsg = "Endung darf nicht leer sein"
250+ continue
251+ }
252+ return []string {value }, nil
253+ }
254+ }
255+
92256func (a * App ) askPort (edition ping.Edition ) (int , error ) {
93257 defaultPort := ping .DefaultPort (edition )
94258 var errMsg string
@@ -114,6 +278,15 @@ func (a *App) askPort(edition ping.Edition) (int, error) {
114278}
115279
116280func (a * App ) execute (config Config ) error {
281+ switch config .Mode {
282+ case ModeLookup :
283+ return a .executeLookup (config .Lookup )
284+ default :
285+ return a .executeDirect (config .Direct )
286+ }
287+ }
288+
289+ func (a * App ) executeDirect (config DirectConfig ) error {
117290 ctx , cancel := context .WithTimeout (context .Background (), a .inputTimeout )
118291 defer cancel ()
119292
@@ -132,10 +305,57 @@ func (a *App) execute(config Config) error {
132305 return nil
133306}
134307
308+ func (a * App ) executeLookup (config LookupConfig ) error {
309+ ctx := context .Background ()
310+
311+ resultText , err := withSpinner ("IP Lookup" , "Domains werden überprüft" , 120 * time .Millisecond , func () (string , error ) {
312+ result , lookupErr := ping .LookupDomains (ctx , ping.LookupConfig {
313+ Edition : config .Edition ,
314+ Port : config .Port ,
315+ BaseHost : config .BaseHost ,
316+ Subdomains : config .Subdomains ,
317+ DomainEndings : config .Endings ,
318+ Concurrency : 24 ,
319+ })
320+ if lookupErr != nil {
321+ return "" , lookupErr
322+ }
323+ return formatLookupResult (result ), nil
324+ })
325+ if err != nil {
326+ return err
327+ }
328+
329+ renderTextPage ("Ergebnis" , resultText )
330+ return nil
331+ }
332+
135333func (a * App ) askAgain () (bool , error ) {
136334 index , err := selectOption ("Nächster Schritt" , []string {"Neue Abfrage" , "Beenden" })
137335 if err != nil {
138336 return false , err
139337 }
140338 return index == 0 , nil
141339}
340+
341+ func formatLookupResult (result ping.LookupResult ) string {
342+ var builder strings.Builder
343+ builder .WriteString (fmt .Sprintf ("Kombinationen geprüft: %d/%d\n " , result .Completed , result .Attempts ))
344+ builder .WriteString (fmt .Sprintf ("Treffer: %d\n " , len (result .Matches )))
345+ builder .WriteString ("\n " )
346+
347+ if len (result .Matches ) == 0 {
348+ builder .WriteString ("Keine passenden Server gefunden." )
349+ return builder .String ()
350+ }
351+
352+ for i , match := range result .Matches {
353+ if i > 0 {
354+ builder .WriteString ("\n " )
355+ }
356+ builder .WriteString (fmt .Sprintf ("Host: %s\n " , match .Host ))
357+ builder .WriteString (match .Result .String ())
358+ builder .WriteString ("\n " )
359+ }
360+ return builder .String ()
361+ }
0 commit comments