@@ -200,12 +200,12 @@ func (w *ProcessWatcher) processEntry(state *scanState, entry portEntry) {
200200 return
201201 }
202202
203- subdomain , needsCustomMapping := w .buildSubdomain (basePath , cwd , state .ignoredDirs )
204- if subdomain == "" && ! needsCustomMapping {
203+ result := w .buildSubdomain (basePath , cwd , state .ignoredDirs )
204+ if result . subdomain == "" && ! result . needsCustomMapping {
205205 return
206206 }
207207
208- w .addListeningProcess (state , pid , entry .Endpoint , subdomain , cwd , needsCustomMapping )
208+ w .addListeningProcess (state , pid , entry .Endpoint , result , cwd )
209209 state .usedPorts [entry .Endpoint .Port ()] = true
210210}
211211
@@ -247,19 +247,21 @@ func (w *ProcessWatcher) addWellKnownProcess(state *scanState, pid int, endpoint
247247 state .usedPorts [port ] = true
248248}
249249
250- func (w * ProcessWatcher ) addListeningProcess (state * scanState , pid int , endpoint netip.AddrPort , subdomain string , cwd string , needsCustomMapping bool ) {
250+ func (w * ProcessWatcher ) addListeningProcess (state * scanState , pid int , endpoint netip.AddrPort , result subdomainResult , cwd string ) {
251251 if state .seenPID [pid ] {
252252 return
253253 }
254254 state .results = append (state .results , DiscoveredService {
255- Subdomain : subdomain ,
255+ Subdomain : result . subdomain ,
256256 Endpoint : endpoint ,
257257 Source : RouteSourceProcess ,
258258 Process : & ProcessInfo {
259259 PID : pid ,
260260 Cwd : cwd ,
261- Disabled : needsCustomMapping ,
262- NeedsCustomMapping : needsCustomMapping ,
261+ Disabled : result .needsCustomMapping ,
262+ NeedsCustomMapping : result .needsCustomMapping ,
263+ TopLevelFolder : result .topLevelFolder ,
264+ RelativePath : result .relativePath ,
263265 },
264266 })
265267 state .seenPID [pid ] = true
@@ -273,28 +275,46 @@ func (w *ProcessWatcher) handleOutsideBasePath(state *scanState, pid int, endpoi
273275 w .addWellKnownProcess (state , pid , endpoint )
274276}
275277
276- func (w * ProcessWatcher ) buildSubdomain (basePath string , cwd string , ignoredDirs map [string ]bool ) (string , bool ) {
278+ type subdomainResult struct {
279+ subdomain string
280+ needsCustomMapping bool
281+ topLevelFolder string
282+ relativePath string
283+ }
284+
285+ func (w * ProcessWatcher ) buildSubdomain (basePath string , cwd string , ignoredDirs map [string ]bool ) subdomainResult {
277286 rel , err := filepath .Rel (basePath , cwd )
278287 if err != nil {
279- return "" , false
288+ return subdomainResult {}
280289 }
281290
282291 parts := strings .Split (rel , string (filepath .Separator ))
283292 if len (parts ) == 0 || parts [0 ] == "" || parts [0 ] == "." {
284- return "" , false
293+ return subdomainResult {}
285294 }
286295
287296 filteredParts := w .filterPathParts (parts , ignoredDirs )
288297 if len (filteredParts ) == 0 {
289- return "" , false
298+ return subdomainResult {}
290299 }
291300
301+ topLevel := filteredParts [0 ]
302+
292303 if len (filteredParts ) == 1 {
293- subdomain := filteredParts [0 ]
294- return subdomain , false
304+ return subdomainResult {
305+ subdomain : topLevel ,
306+ needsCustomMapping : false ,
307+ topLevelFolder : topLevel ,
308+ relativePath : topLevel ,
309+ }
295310 }
296311
297- return "" , true
312+ return subdomainResult {
313+ subdomain : topLevel ,
314+ needsCustomMapping : true ,
315+ topLevelFolder : topLevel ,
316+ relativePath : strings .Join (filteredParts , "/" ),
317+ }
298318}
299319
300320func (w * ProcessWatcher ) filterPathParts (parts []string , ignoredDirs map [string ]bool ) []string {
0 commit comments