Now displaying agent number instead of id.
Passing timezone to server side for rendering of time stamps Configuration of preferred shells.
This commit is contained in:
		
							parent
							
								
									d6fc2e4118
								
							
						
					
					
						commit
						e141007f0a
					
				| @ -174,7 +174,11 @@ func printHelp(msg string) { | |||||||
| 		"--warning-time:     advance warning time before sessio ends\n" + | 		"--warning-time:     advance warning time before sessio ends\n" + | ||||||
| 		"--expiry-time:      expiry time of the session\n" + | 		"--expiry-time:      expiry time of the session\n" + | ||||||
| 		"--check-interval:   interval at which expiry is checked\n" + | 		"--check-interval:   interval at which expiry is checked\n" + | ||||||
| 		"-insecure:          allow invalid certificates\n" | 		"--insecure:         allow invalid certificates\n" + | ||||||
|  | 		"--shells:           comma-separated list of shells to add to the front of theshell search path\n" + | ||||||
|  | 		"                    (e.g. 'zsh,sh'). If the shell name contains a slash,then the path must exist:\n" + | ||||||
|  | 		"                    either relative to the agent's current directory or absolute. Otherwise it is looekd\n" + | ||||||
|  | 		"                    up in the system search path. " | ||||||
| 
 | 
 | ||||||
| 	fmt.Fprintln(os.Stderr, helpText) | 	fmt.Fprintln(os.Stderr, helpText) | ||||||
| 	os.Exit(1) | 	os.Exit(1) | ||||||
| @ -211,8 +215,14 @@ func main() { | |||||||
| 	agentExpriryTime := 10 * time.Minute | 	agentExpriryTime := 10 * time.Minute | ||||||
| 	tickerInterval := 60 * time.Second | 	tickerInterval := 60 * time.Second | ||||||
| 	insecure := false | 	insecure := false | ||||||
|  | 	shells := []string{"bash", "sh", "ash", "ksh", "zsh", "fish", "tcsh", "csh"} | ||||||
|  | 	if runtime.GOOS == "windows" { | ||||||
|  | 		shells = []string{"powershell", "bash"} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	args := os.Args[1:] | 	args := os.Args[1:] | ||||||
|  | 	additionalShells := []string{} | ||||||
|  | 	commaSeparated := "" | ||||||
| 	for len(args) > 0 && strings.HasPrefix(args[0], "-") { | 	for len(args) > 0 && strings.HasPrefix(args[0], "-") { | ||||||
| 		val := "" | 		val := "" | ||||||
| 		switch args[0] { | 		switch args[0] { | ||||||
| @ -228,12 +238,17 @@ func main() { | |||||||
| 			tickerInterval, args = parseDuration(args, val) | 			tickerInterval, args = parseDuration(args, val) | ||||||
| 		case "--insecure": | 		case "--insecure": | ||||||
| 			insecure = true | 			insecure = true | ||||||
|  | 		case "--shells": | ||||||
|  | 			commaSeparated, args = getArg(args) | ||||||
|  | 			additionalShells = append(additionalShells, strings.Split(commaSeparated, ",")...) | ||||||
| 		default: | 		default: | ||||||
| 			printHelp("Unknown option " + args[0]) | 			printHelp("Unknown option " + args[0]) | ||||||
| 		} | 		} | ||||||
| 		args = args[1:] | 		args = args[1:] | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	shells = append(additionalShells, shells...) | ||||||
|  | 
 | ||||||
| 	id = getId(id) | 	id = getId(id) | ||||||
| 
 | 
 | ||||||
| 	if len(args) != 1 { | 	if len(args) != 1 { | ||||||
| @ -266,7 +281,7 @@ func main() { | |||||||
| 	wsConn := websocketutil.NewWebSocketConn(conn, false) | 	wsConn := websocketutil.NewWebSocketConn(conn, false) | ||||||
| 	defer wsConn.Close() | 	defer wsConn.Close() | ||||||
| 
 | 
 | ||||||
| 	shell := chooseShell() | 	shell := chooseShell(shells) | ||||||
| 	serverInfo, err := comms.AgentInitialization(wsConn, comms.NewAgentInfo(shell)) | 	serverInfo, err := comms.AgentInitialization(wsConn, comms.NewAgentInfo(shell)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Printf("ERROR: %v", err) | 		log.Printf("ERROR: %v", err) | ||||||
| @ -355,14 +370,9 @@ func setupAuthentication(commChannel comms.CommChannel, | |||||||
| 	return passwordHandler, authorizedKeys | 	return passwordHandler, authorizedKeys | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func chooseShell() string { | func chooseShell(shells []string) string { | ||||||
|  | 	log.Printf("Shell search path is %v", shells) | ||||||
| 	var err error | 	var err error | ||||||
| 
 |  | ||||||
| 	shells := []string{"bash", "sh", "ash", "ksh", "zsh", "fish", "tcsh", "csh"} |  | ||||||
| 	if runtime.GOOS == "windows" { |  | ||||||
| 		shells = []string{"powershell", "bash"} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	shell := "" | 	shell := "" | ||||||
| 	for _, candidate := range shells { | 	for _, candidate := range shells { | ||||||
| 		shell, err = exec.LookPath(candidate) | 		shell, err = exec.LookPath(candidate) | ||||||
|  | |||||||
| @ -61,8 +61,9 @@ func main() { | |||||||
| 
 | 
 | ||||||
| 		state := models.State{} | 		state := models.State{} | ||||||
| 		agent := models.Agent{ | 		agent := models.Agent{ | ||||||
| 			PublicId:  "id", | 			PublicId:    "id", | ||||||
| 			StartTime: time.Now().In(japan), | 			GeneratedId: "100", | ||||||
|  | 			StartTime:   time.Now().In(japan), | ||||||
| 			AgentInfo: comms.AgentInfo{ | 			AgentInfo: comms.AgentInfo{ | ||||||
| 				Username: "ci", | 				Username: "ci", | ||||||
| 				Hostname: "container123", | 				Hostname: "container123", | ||||||
| @ -75,6 +76,7 @@ func main() { | |||||||
| 		state.Agents = append(state.Agents, agent) | 		state.Agents = append(state.Agents, agent) | ||||||
| 		client := models.Client{ | 		client := models.Client{ | ||||||
| 			PublicId:    "c1", | 			PublicId:    "c1", | ||||||
|  | 			AgentId:     "100", | ||||||
| 			ClientId:    3, | 			ClientId:    3, | ||||||
| 			StartTime:   time.Now().In(japan), | 			StartTime:   time.Now().In(japan), | ||||||
| 			SessionType: "sftp", | 			SessionType: "sftp", | ||||||
|  | |||||||
| @ -6,8 +6,9 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Agent struct { | type Agent struct { | ||||||
| 	PublicId  string | 	PublicId    string | ||||||
| 	StartTime time.Time | 	GeneratedId string | ||||||
|  | 	StartTime   time.Time | ||||||
| 
 | 
 | ||||||
| 	AgentInfo  comms.AgentInfo | 	AgentInfo  comms.AgentInfo | ||||||
| 	ExpiryTime time.Time | 	ExpiryTime time.Time | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| type Client struct { | type Client struct { | ||||||
| 	PublicId    string | 	PublicId    string | ||||||
|  | 	AgentId     string | ||||||
| 	ClientId    int | 	ClientId    int | ||||||
| 	StartTime   time.Time | 	StartTime   time.Time | ||||||
| 	SessionType string | 	SessionType string | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ type AgentConnection struct { | |||||||
| 	commChannel comms.CommChannel | 	commChannel comms.CommChannel | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var agentIdGenerator = concurrency.NewAtomicCounter() | ||||||
| var clientIdGenerator = concurrency.NewAtomicCounter() | var clientIdGenerator = concurrency.NewAtomicCounter() | ||||||
| 
 | 
 | ||||||
| type ClientConnection struct { | type ClientConnection struct { | ||||||
| @ -32,19 +33,21 @@ type ClientConnection struct { | |||||||
| func NewAgent(commChannel comms.CommChannel, publicId string, agentInfo comms.AgentInfo) *AgentConnection { | func NewAgent(commChannel comms.CommChannel, publicId string, agentInfo comms.AgentInfo) *AgentConnection { | ||||||
| 	return &AgentConnection{ | 	return &AgentConnection{ | ||||||
| 		Agent: models.Agent{ | 		Agent: models.Agent{ | ||||||
| 			PublicId:  publicId, | 			PublicId:    publicId, | ||||||
| 			StartTime: time.Now(), | 			GeneratedId: strconv.Itoa(agentIdGenerator.IncrementAndGet()), | ||||||
| 			AgentInfo: agentInfo, | 			StartTime:   time.Now(), | ||||||
|  | 			AgentInfo:   agentInfo, | ||||||
| 		}, | 		}, | ||||||
| 		commChannel: commChannel, | 		commChannel: commChannel, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewClient(publicId string, clientConn iowrappers2.ReadWriteAddrCloser, | func NewClient(publicId string, agentId string, clientConn iowrappers2.ReadWriteAddrCloser, | ||||||
| 	agentConn net.Conn) *ClientConnection { | 	agentConn net.Conn) *ClientConnection { | ||||||
| 	return &ClientConnection{ | 	return &ClientConnection{ | ||||||
| 		Client: models.Client{ | 		Client: models.Client{ | ||||||
| 			PublicId:  publicId, | 			PublicId:  publicId, | ||||||
|  | 			AgentId:   agentId, | ||||||
| 			ClientId:  clientIdGenerator.IncrementAndGet(), | 			ClientId:  clientIdGenerator.IncrementAndGet(), | ||||||
| 			StartTime: time.Now(), | 			StartTime: time.Now(), | ||||||
| 		}, | 		}, | ||||||
| @ -197,7 +200,7 @@ func (admin *Admin) addClient(publicId string, clientConn iowrappers2.ReadWriteA | |||||||
| 
 | 
 | ||||||
| 	log.Println("Sending connection information to agent") | 	log.Println("Sending connection information to agent") | ||||||
| 
 | 
 | ||||||
| 	client := NewClient(publicId, clientConn, agentConn) | 	client := NewClient(publicId, agent.GeneratedId, clientConn, agentConn) | ||||||
| 
 | 
 | ||||||
| 	// Before using this connection for SSH we use it to send client metadata to the
 | 	// Before using this connection for SSH we use it to send client metadata to the
 | ||||||
| 	// agent
 | 	// agent
 | ||||||
|  | |||||||
| @ -59,20 +59,14 @@ func (sessions *WebSessions) NewSession(wsConnection net.Conn) *WebSession { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetUserLocation(r *http.Request) (*time.Location, error) { | func GetUserLocation(r *http.Request) (*time.Location, error) { | ||||||
| 	// Try to get timezone from a custom header
 | 	tzName := r.URL.Query().Get("timezone") | ||||||
| 	tzName := r.Header.Get("X-Timezone") |  | ||||||
| 
 |  | ||||||
| 	// If not found in header, try to get from query parameter
 |  | ||||||
| 	if tzName == "" { | 	if tzName == "" { | ||||||
| 		tzName = r.URL.Query().Get("tz") | 		tzName = r.Header.Get("X-Timezone") | ||||||
| 	} | 	} | ||||||
| 
 | 	//log.Println("GetUserLocation: timezone ", tzName)
 | ||||||
| 	// If still not found, default to UTC
 |  | ||||||
| 	if tzName == "" { | 	if tzName == "" { | ||||||
| 		tzName = "UTC" | 		tzName = "UTC" | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	// Load the location
 |  | ||||||
| 	return time.LoadLocation(tzName) | 	return time.LoadLocation(tzName) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -24,15 +24,36 @@ templ BasePage(tab int) { | |||||||
|         <title>Converge</title> |         <title>Converge</title> | ||||||
|     </head> |     </head> | ||||||
|     <body> |     <body> | ||||||
|     <script> |     <!-- script> | ||||||
|     htmx.logAll(); |     htmx.logAll(); | ||||||
|  |     </script --> | ||||||
|  |     <script> | ||||||
|  |         function getTimezone() { | ||||||
|  |             return Intl.DateTimeFormat().resolvedOptions().timeZone; | ||||||
|  |         } | ||||||
|  |         if (!window.originalWebSocket) { | ||||||
|  |             console.log("timezone override for websockets") | ||||||
|  |             window.originalWebSocket = htmx.createWebSocket | ||||||
|  |             htmx.createWebSocket = function(url) { | ||||||
|  |                 let modifiedUrl = url + "?timezone=" + getTimezone() | ||||||
|  |                 return window.originalWebSocket(modifiedUrl) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         document.body.addEventListener( | ||||||
|  |             "htmx:configRequest", | ||||||
|  |             function(evt) { | ||||||
|  |                 console.log("Adding timezone to htmx request headers"); | ||||||
|  |                 evt.detail.headers["X-Timezone"] = getTimezone(); | ||||||
|  |             } | ||||||
|  |         ); | ||||||
|     </script> |     </script> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     <script src="../static/js/bootstrap.bundle.min.js" |     <script src="../static/js/bootstrap.bundle.min.js" | ||||||
|             crossorigin="anonymous"></script> |             crossorigin="anonymous"></script> | ||||||
| 
 | 
 | ||||||
|     <div class="container-fluid"> |     <div class="container-fluid" hx-boost="true"> | ||||||
|         <div class="row"> |         <div class="row"> | ||||||
|             <div class="col"> |             <div class="col"> | ||||||
|                 <nav class="navbar navbar-expand-sm navbar-light bg-light"> |                 <nav class="navbar navbar-expand-sm navbar-light bg-light"> | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ templ State(state *models.State, location *time.Location) { | |||||||
|            </thead> |            </thead> | ||||||
|    for _, agent := range state.Agents { |    for _, agent := range state.Agents { | ||||||
|            <tr> |            <tr> | ||||||
|                <td>{agent.PublicId}</td> |                <td>{agent.GeneratedId}</td> | ||||||
|                <td>{agent.StartTime.In(location).Format(time.DateTime)}</td> |                <td>{agent.StartTime.In(location).Format(time.DateTime)}</td> | ||||||
|                <td>{agent.ExpiryTime.In(location).Format(time.DateTime)}</td> |                <td>{agent.ExpiryTime.In(location).Format(time.DateTime)}</td> | ||||||
|                <td>{agent.AgentInfo.Username}</td> |                <td>{agent.AgentInfo.Username}</td> | ||||||
| @ -75,7 +75,7 @@ templ State(state *models.State, location *time.Location) { | |||||||
|               </thead> |               </thead> | ||||||
|    for _, client := range state.Clients { |    for _, client := range state.Clients { | ||||||
|               <tr> |               <tr> | ||||||
|                   <td>{client.PublicId}</td> |                   <td>{client.AgentId}</td> | ||||||
|                   <td>{strconv.Itoa(client.ClientId)}</td> |                   <td>{strconv.Itoa(client.ClientId)}</td> | ||||||
|                   <td>{client.StartTime.In(location).Format(time.DateTime)}</td> |                   <td>{client.StartTime.In(location).Format(time.DateTime)}</td> | ||||||
|                   <td>{client.SessionType}</td> |                   <td>{client.SessionType}</td> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user