Skip to content

Commit 2a9b9be

Browse files
committed
Merge branch 'main' of github.com:coder/coder into bq/fe/update-user-password
2 parents d35139c + 57bb108 commit 2a9b9be

File tree

26 files changed

+372
-126
lines changed

26 files changed

+372
-126
lines changed

cli/cliui/agent.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"os"
8+
"os/signal"
79
"sync"
810
"time"
911

@@ -46,6 +48,23 @@ func Agent(ctx context.Context, writer io.Writer, opts AgentOptions) error {
4648
spin.Start()
4749
defer spin.Stop()
4850

51+
ctx, cancelFunc := context.WithCancel(ctx)
52+
defer cancelFunc()
53+
stopSpin := make(chan os.Signal, 1)
54+
signal.Notify(stopSpin, os.Interrupt)
55+
defer signal.Stop(stopSpin)
56+
go func() {
57+
select {
58+
case <-ctx.Done():
59+
return
60+
case <-stopSpin:
61+
}
62+
signal.Stop(stopSpin)
63+
spin.Stop()
64+
// nolint:revive
65+
os.Exit(1)
66+
}()
67+
4968
ticker := time.NewTicker(opts.FetchInterval)
5069
defer ticker.Stop()
5170
timer := time.NewTimer(opts.WarnInterval)

cli/login.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,19 @@ func login() *cobra.Command {
117117
if err != nil {
118118
return xerrors.Errorf("specify password prompt: %w", err)
119119
}
120+
_, err = cliui.Prompt(cmd, cliui.PromptOptions{
121+
Text: "Confirm " + cliui.Styles.Field.Render("password") + ":",
122+
Secret: true,
123+
Validate: func(s string) error {
124+
if s != password {
125+
return xerrors.Errorf("Passwords do not match")
126+
}
127+
return nil
128+
},
129+
})
130+
if err != nil {
131+
return xerrors.Errorf("confirm password prompt: %w", err)
132+
}
120133

121134
_, err = client.CreateFirstUser(cmd.Context(), codersdk.CreateFirstUserRequest{
122135
Email: email,

cli/login_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func TestLogin(t *testing.T) {
4343
"username", "testuser",
4444
"email", "user@coder.com",
4545
"password", "password",
46+
"password", "password", // Confirm.
4647
}
4748
for i := 0; i < len(matches); i += 2 {
4849
match := matches[i]
@@ -54,6 +55,44 @@ func TestLogin(t *testing.T) {
5455
<-doneChan
5556
})
5657

58+
t.Run("InitialUserTTYConfirmPasswordFailAndReprompt", func(t *testing.T) {
59+
t.Parallel()
60+
ctx, cancel := context.WithCancel(context.Background())
61+
defer cancel()
62+
client := coderdtest.New(t, nil)
63+
// The --force-tty flag is required on Windows, because the `isatty` library does not
64+
// accurately detect Windows ptys when they are not attached to a process:
65+
// https://github.com/mattn/go-isatty/issues/59
66+
doneChan := make(chan struct{})
67+
root, _ := clitest.New(t, "login", "--force-tty", client.URL.String())
68+
pty := ptytest.New(t)
69+
root.SetIn(pty.Input())
70+
root.SetOut(pty.Output())
71+
go func() {
72+
defer close(doneChan)
73+
err := root.ExecuteContext(ctx)
74+
require.ErrorIs(t, err, context.Canceled)
75+
}()
76+
77+
matches := []string{
78+
"first user?", "yes",
79+
"username", "testuser",
80+
"email", "user@coder.com",
81+
"password", "mypass",
82+
"password", "wrongpass", // Confirm.
83+
}
84+
for i := 0; i < len(matches); i += 2 {
85+
match := matches[i]
86+
value := matches[i+1]
87+
pty.ExpectMatch(match)
88+
pty.WriteLine(value)
89+
}
90+
pty.ExpectMatch("Passwords do not match")
91+
pty.ExpectMatch("password") // Re-prompt password.
92+
cancel()
93+
<-doneChan
94+
})
95+
5796
t.Run("ExistingUserValidTokenTTY", func(t *testing.T) {
5897
t.Parallel()
5998
client := coderdtest.New(t, nil)

coderd/httpmw/userparam.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,6 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
7676
}
7777
}
7878

79-
apiKey := APIKey(r)
80-
if apiKey.UserID != user.ID {
81-
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
82-
Message: "getting non-personal users isn't supported yet",
83-
})
84-
return
85-
}
86-
8779
ctx := context.WithValue(r.Context(), userParamContextKey{}, user)
8880
next.ServeHTTP(rw, r.WithContext(ctx))
8981
})

coderd/users.go

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -361,29 +361,14 @@ func (api *api) putUserSuspend(rw http.ResponseWriter, r *http.Request) {
361361
}
362362

363363
func (api *api) putUserPassword(rw http.ResponseWriter, r *http.Request) {
364-
user := httpmw.UserParam(r)
365-
366-
var params codersdk.UpdateUserPasswordRequest
364+
var (
365+
user = httpmw.UserParam(r)
366+
params codersdk.UpdateUserPasswordRequest
367+
)
367368
if !httpapi.Read(rw, r, &params) {
368369
return
369370
}
370371

371-
// Check if the new password and the confirmation match
372-
if params.Password != params.ConfirmPassword {
373-
requestErrors := []httpapi.Error{
374-
{
375-
Field: "confirm_new_password",
376-
Detail: "The value does not match the new password",
377-
},
378-
}
379-
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
380-
Message: fmt.Sprintf("The new password and the new password confirmation don't match"),
381-
Errors: requestErrors,
382-
})
383-
return
384-
}
385-
386-
// Hash password and update it in the database
387372
hashedPassword, err := userpassword.Hash(params.Password)
388373
if err != nil {
389374
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{

coderd/users_test.go

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -290,35 +290,38 @@ func TestUpdateUserProfile(t *testing.T) {
290290
func TestUpdateUserPassword(t *testing.T) {
291291
t.Parallel()
292292

293-
t.Run("DifferentPasswordConfirmation", func(t *testing.T) {
293+
t.Run("MemberCantUpdateAdminPassword", func(t *testing.T) {
294294
t.Parallel()
295295
client := coderdtest.New(t, nil)
296-
coderdtest.CreateFirstUser(t, client)
297-
err := client.UpdateUserPassword(context.Background(), codersdk.Me, codersdk.UpdateUserPasswordRequest{
298-
Password: "newpassword",
299-
ConfirmPassword: "wrongconfirmation",
296+
admin := coderdtest.CreateFirstUser(t, client)
297+
member := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
298+
err := member.UpdateUserPassword(context.Background(), admin.UserID, codersdk.UpdateUserPasswordRequest{
299+
Password: "newpassword",
300300
})
301-
var apiErr *codersdk.Error
302-
require.ErrorAs(t, err, &apiErr)
303-
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
301+
require.Error(t, err, "member should not be able to update admin password")
304302
})
305303

306-
t.Run("Success", func(t *testing.T) {
304+
t.Run("AdminCanUpdateMemberPassword", func(t *testing.T) {
307305
t.Parallel()
308306
client := coderdtest.New(t, nil)
309-
coderdtest.CreateFirstUser(t, client)
310-
err := client.UpdateUserPassword(context.Background(), codersdk.Me, codersdk.UpdateUserPasswordRequest{
311-
Password: "newpassword",
312-
ConfirmPassword: "newpassword",
307+
admin := coderdtest.CreateFirstUser(t, client)
308+
member, err := client.CreateUser(context.Background(), codersdk.CreateUserRequest{
309+
Email: "coder@coder.com",
310+
Username: "coder",
311+
Password: "password",
312+
OrganizationID: admin.OrganizationID,
313313
})
314-
require.NoError(t, err, "update password request should be successful")
315-
316-
// Check if the user can login using the new password
314+
require.NoError(t, err, "create member")
315+
err = client.UpdateUserPassword(context.Background(), member.ID, codersdk.UpdateUserPasswordRequest{
316+
Password: "newpassword",
317+
})
318+
require.NoError(t, err, "admin should be able to update member password")
319+
// Check if the member can login using the new password
317320
_, err = client.LoginWithPassword(context.Background(), codersdk.LoginWithPasswordRequest{
318-
Email: coderdtest.FirstUserParams.Email,
321+
Email: "coder@coder.com",
319322
Password: "newpassword",
320323
})
321-
require.NoError(t, err, "login should be successful")
324+
require.NoError(t, err, "member should login successfully with the new password")
322325
})
323326
}
324327

codersdk/users.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ type UpdateUserProfileRequest struct {
7373
}
7474

7575
type UpdateUserPasswordRequest struct {
76-
Password string `json:"password" validate:"required"`
77-
ConfirmPassword string `json:"confirm_new_password" validate:"required"`
76+
Password string `json:"password" validate:"required"`
7877
}
7978

8079
type UpdateRoles struct {

docs/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=soc
1010

1111
Provision remote development environments with Terraform.
1212

13+
![Kubernetes workspace in Coder v2](./screenshot.png)
14+
1315
## Highlights
1416

1517
- Automate development environments for Linux, Windows, and macOS
@@ -100,6 +102,6 @@ Read the [contributing docs](./CONTRIBUTING.md).
100102

101103
<!--- Add your row by date (mm/dd/yyyy), most recent date at end of list --->
102104

103-
| Name | Start Date | First PR Date |Organization| GitHub User Link |
104-
| ------------- | :--------: | :-----------: |:----------:| ------------------------------: |
105-
| Mathias Fredriksson | 04/25/2022 | 04/25/2022 | [Coder](https://github.com/coder) | [mafredri](https://github.com/mafredri) |
105+
| Name | Start Date | First PR Date | Organization | GitHub User Link |
106+
| ------------------- | :--------: | :-----------: | :-------------------------------: | --------------------------------------: |
107+
| Mathias Fredriksson | 04/25/2022 | 04/25/2022 | [Coder](https://github.com/coder) | [mafredri](https://github.com/mafredri) |

docs/screenshot.png

520 KB
Loading

examples/docker-local/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ resource "docker_container" "workspace" {
4242
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}-root"
4343
dns = ["1.1.1.1"]
4444
command = ["sh", "-c", coder_agent.dev.init_script]
45-
env = ["CODER_TOKEN=${coder_agent.dev.token}"]
45+
env = ["CODER_AGENT_TOKEN=${coder_agent.dev.token}"]
4646
volumes {
4747
container_path = "/home/coder/"
4848
volume_name = docker_volume.coder_volume.name

0 commit comments

Comments
 (0)