فهرست منبع

add support for user-defined screen name formatting

This commit introduces two distinct screen name data types:
- IdentScreenName: A normalized version of the screen name used as a
unique identifier. This is stored in the database and used for login
validation, ensuring that users can log in regardless of the format
they use.
- DisplayScreenName: Maintains the user-defined formatting, including
case and spaces, allowing for personalized display.

Additionally, a database migration is included, which adds a new field
identScreenName, for storing the IdentScreenName. The screenName
field is renamed to displayScreenName, which stores the value of
DisplayScreenName.

These changes allow users to register and log in with any screen name
format, as long as the normalized version matches the identifier
stored in the database.

From the API perspective, users continue to have the "screen_name"
field, which is the display screen name.
Mike 2 سال پیش
والد
کامیت
e217539ed1
47فایلهای تغییر یافته به همراه1373 افزوده شده و 1057 حذف شده
  1. 4 4
      README.md
  2. 24 13
      foodgroup/auth.go
  3. 102 85
      foodgroup/auth_test.go
  4. 2 2
      foodgroup/bart_test.go
  5. 12 12
      foodgroup/buddy.go
  6. 44 38
      foodgroup/buddy_test.go
  7. 2 2
      foodgroup/chat.go
  8. 1 1
      foodgroup/chat_nav.go
  9. 2 1
      foodgroup/chat_nav_test.go
  10. 12 12
      foodgroup/feedbag.go
  11. 73 70
      foodgroup/feedbag_test.go
  12. 14 12
      foodgroup/icbm.go
  13. 22 29
      foodgroup/icbm_test.go
  14. 6 4
      foodgroup/locate.go
  15. 22 22
      foodgroup/locate_test.go
  16. 16 16
      foodgroup/mock_chat_message_relayer_test.go
  17. 59 59
      foodgroup/mock_feedbag_manager_test.go
  18. 39 36
      foodgroup/mock_legacy_buddy_list_manager_test.go
  19. 16 16
      foodgroup/mock_message_relayer_test.go
  20. 18 15
      foodgroup/mock_profile_manager_test.go
  21. 17 17
      foodgroup/mock_session_manager_test.go
  22. 8 8
      foodgroup/mock_user_manager_manager_test.go
  23. 5 5
      foodgroup/oservice.go
  24. 36 30
      foodgroup/oservice_test.go
  25. 37 37
      foodgroup/test_helpers.go
  26. 20 20
      foodgroup/types.go
  27. 38 54
      server/http/mgmt_api.go
  28. 48 30
      server/http/mgmt_api_test.go
  29. 14 14
      server/http/mock_user_manager_test.go
  30. 3 3
      server/oscar/auth.go
  31. 4 3
      server/oscar/bos.go
  32. 1 1
      server/oscar/bos_test.go
  33. 1 1
      server/oscar/chat.go
  34. 1 1
      server/oscar/connection_test.go
  35. 1 1
      server/oscar/middleware/logger.go
  36. 38 38
      server/oscar/mock_auth_test.go
  37. 10 10
      state/buddy_list_store.go
  38. 49 38
      state/buddy_list_store_test.go
  39. 16 0
      state/migrations/0003_formatted_screen_name.down.sql
  40. 27 0
      state/migrations/0003_formatted_screen_name.up.sql
  41. 37 22
      state/session.go
  42. 20 18
      state/session_manager.go
  43. 43 52
      state/session_manager_test.go
  44. 6 5
      state/session_test.go
  45. 122 0
      state/user.go
  46. 68 123
      state/user_store.go
  47. 213 77
      state/user_store_test.go

+ 4 - 4
README.md

@@ -65,7 +65,7 @@ Invoke-WebRequest -Uri http://localhost:8080/user -Method Get
 
 
 ```powershell
 ```powershell
 Invoke-WebRequest -Uri http://localhost:8080/user `
 Invoke-WebRequest -Uri http://localhost:8080/user `
-  -Body '{"screen_name":"myscreenname", "password":"thepassword"}' `
+  -Body '{"screen_name":"MyScreenName", "password":"thepassword"}' `
   -Method Post `
   -Method Post `
   -ContentType "application/json"
   -ContentType "application/json"
 ```
 ```
@@ -83,7 +83,7 @@ Invoke-WebRequest -Uri http://localhost:8080/user `
 
 
 ```powershell
 ```powershell
 Invoke-WebRequest -Uri http://localhost:8080/user/password `
 Invoke-WebRequest -Uri http://localhost:8080/user/password `
-  -Body '{"screen_name":"myscreenname", "password":"thenewpassword"}' `
+  -Body '{"screen_name":"MyScreenName", "password":"thenewpassword"}' `
   -Method Put `
   -Method Put `
   -ContentType "application/json"
   -ContentType "application/json"
 ```
 ```
@@ -107,7 +107,7 @@ curl http://localhost:8080/user
 #### Create Users
 #### Create Users
 
 
 ```shell
 ```shell
-curl -d'{"screen_name":"myscreenname", "password":"thepassword"}' http://localhost:8080/user
+curl -d'{"screen_name":"MyScreenName", "password":"thepassword"}' http://localhost:8080/user
 ```
 ```
 
 
 #### Delete Users
 #### Delete Users
@@ -119,7 +119,7 @@ curl -X DELETE -d '{"screen_name": "user123"}' http://localhost:8080/user
 #### Change Password
 #### Change Password
 
 
 ```shell
 ```shell
-curl -X PUT -d'{"screen_name":"myscreenname", "password":"thenewpassword"}' http://localhost:8080/user/password
+curl -X PUT -d'{"screen_name":"MyScreenName", "password":"thenewpassword"}' http://localhost:8080/user/password
 ```
 ```
 
 
 #### List Active Sessions
 #### List Active Sessions

+ 24 - 13
foodgroup/auth.go

@@ -58,14 +58,28 @@ func (s AuthService) RegisterChatSession(loginCookie []byte) (*state.Session, er
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	chatSess := chatSessMgr.(SessionManager).AddSession(c.ScreenName)
+	u, err := s.userManager.User(state.NewIdentScreenName(c.ScreenName))
+	if err != nil {
+		return nil, fmt.Errorf("failed to retrieve user: %w", err)
+	}
+	if u == nil {
+		return nil, fmt.Errorf("user not found")
+	}
+	chatSess := chatSessMgr.(SessionManager).AddSession(u.DisplayScreenName)
 	chatSess.SetChatRoomCookie(room.Cookie)
 	chatSess.SetChatRoomCookie(room.Cookie)
 	return chatSess, nil
 	return chatSess, nil
 }
 }
 
 
 // RegisterBOSSession creates and returns a user's session.
 // RegisterBOSSession creates and returns a user's session.
-func (s AuthService) RegisterBOSSession(sessionID string) (*state.Session, error) {
-	return s.sessionManager.AddSession(sessionID), nil
+func (s AuthService) RegisterBOSSession(screenName state.IdentScreenName) (*state.Session, error) {
+	u, err := s.userManager.User(screenName)
+	if err != nil {
+		return nil, fmt.Errorf("failed to retrieve user: %w", err)
+	}
+	if u == nil {
+		return nil, fmt.Errorf("user not found")
+	}
+	return s.sessionManager.AddSession(u.DisplayScreenName), nil
 }
 }
 
 
 // Signout removes this user's session and notifies users who have this user on
 // Signout removes this user's session and notifies users who have this user on
@@ -75,7 +89,7 @@ func (s AuthService) Signout(ctx context.Context, sess *state.Session) error {
 		return err
 		return err
 	}
 	}
 	s.sessionManager.RemoveSession(sess)
 	s.sessionManager.RemoveSession(sess)
-	s.legacyBuddyListManager.DeleteUser(sess.ScreenName())
+	s.legacyBuddyListManager.DeleteUser(sess.IdentScreenName())
 	return nil
 	return nil
 }
 }
 
 
@@ -113,7 +127,7 @@ func (s AuthService) BUCPChallenge(
 
 
 	var authKey string
 	var authKey string
 
 
-	user, err := s.userManager.User(screenName)
+	user, err := s.userManager.User(state.NewIdentScreenName(screenName))
 	if err != nil {
 	if err != nil {
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
 	}
 	}
@@ -163,10 +177,7 @@ func (s AuthService) BUCPChallenge(
 // (wire.LoginTLVTagsReconnectHere) and an authorization cookie
 // (wire.LoginTLVTagsReconnectHere) and an authorization cookie
 // (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
 // (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
 // (wire.LoginTLVTagsErrorSubcode).
 // (wire.LoginTLVTagsErrorSubcode).
-func (s AuthService) BUCPLogin(
-	bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest,
-	newUserFn func(screenName string) (state.User, error),
-) (wire.SNACMessage, error) {
+func (s AuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
 
 
 	block, err := s.login(bodyIn.TLVList, newUserFn)
 	block, err := s.login(bodyIn.TLVList, newUserFn)
 	if err != nil {
 	if err != nil {
@@ -194,7 +205,7 @@ func (s AuthService) BUCPLogin(
 // (wire.LoginTLVTagsReconnectHere) and an authorization cookie
 // (wire.LoginTLVTagsReconnectHere) and an authorization cookie
 // (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
 // (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
 // (wire.LoginTLVTagsErrorSubcode).
 // (wire.LoginTLVTagsErrorSubcode).
-func (s AuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName string) (state.User, error)) (wire.TLVRestBlock, error) {
+func (s AuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
 	return s.login(frame.TLVList, newUserFn)
 	return s.login(frame.TLVList, newUserFn)
 }
 }
 
 
@@ -202,7 +213,7 @@ func (s AuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screen
 // metadata used in both BUCP and FLAP authentication responses.
 // metadata used in both BUCP and FLAP authentication responses.
 func (s AuthService) login(
 func (s AuthService) login(
 	TLVList wire.TLVList,
 	TLVList wire.TLVList,
-	newUserFn func(screenName string) (state.User, error),
+	newUserFn func(screenName state.DisplayScreenName) (state.User, error),
 ) (wire.TLVRestBlock, error) {
 ) (wire.TLVRestBlock, error) {
 
 
 	screenName, found := TLVList.String(wire.LoginTLVTagsScreenName)
 	screenName, found := TLVList.String(wire.LoginTLVTagsScreenName)
@@ -210,7 +221,7 @@ func (s AuthService) login(
 		return wire.TLVRestBlock{}, errors.New("screen name doesn't exist in tlv")
 		return wire.TLVRestBlock{}, errors.New("screen name doesn't exist in tlv")
 	}
 	}
 
 
-	user, err := s.userManager.User(screenName)
+	user, err := s.userManager.User(state.NewIdentScreenName(screenName))
 	if err != nil {
 	if err != nil {
 		return wire.TLVRestBlock{}, err
 		return wire.TLVRestBlock{}, err
 	}
 	}
@@ -230,7 +241,7 @@ func (s AuthService) login(
 		if !loginOK {
 		if !loginOK {
 			// make login succeed anyway. create new user if the account
 			// make login succeed anyway. create new user if the account
 			// doesn't already exist.
 			// doesn't already exist.
-			newUser, err := newUserFn(screenName)
+			newUser, err := newUserFn(state.DisplayScreenName(screenName))
 			if err != nil {
 			if err != nil {
 				return wire.TLVRestBlock{}, err
 				return wire.TLVRestBlock{}, err
 			}
 			}

+ 102 - 85
foodgroup/auth_test.go

@@ -16,8 +16,8 @@ import (
 
 
 func TestAuthService_BUCPLoginRequest(t *testing.T) {
 func TestAuthService_BUCPLoginRequest(t *testing.T) {
 	user := state.User{
 	user := state.User{
-		ScreenName: "screen_name",
-		AuthKey:    "auth_key",
+		IdentScreenName: state.NewIdentScreenName("screen_name"),
+		AuthKey:         "auth_key",
 	}
 	}
 	assert.NoError(t, user.HashPassword("the_password"))
 	assert.NoError(t, user.HashPassword("the_password"))
 
 
@@ -32,7 +32,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 		// method's dependencies
 		// method's dependencies
 		mockParams mockParams
 		mockParams mockParams
 		// newUserFn is the function that registers a new user account
 		// newUserFn is the function that registers a new user account
-		newUserFn func(screenName string) (state.User, error)
+		newUserFn func(screenName state.DisplayScreenName) (state.User, error)
 		// expectOutput is the SNAC sent from the server to client
 		// expectOutput is the SNAC sent from the server to client
 		expectOutput wire.SNACMessage
 		expectOutput wire.SNACMessage
 		// wantErr is the error we expect from the method
 		// wantErr is the error we expect from the method
@@ -48,7 +48,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -56,14 +56,14 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
@@ -76,7 +76,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 					TLVRestBlock: wire.TLVRestBlock{
 					TLVRestBlock: wire.TLVRestBlock{
 						TLVList: wire.TLVList{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+							wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 						},
 						},
@@ -95,7 +95,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -103,7 +103,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     nil,
 							result:     nil,
 						},
 						},
 					},
 					},
@@ -115,12 +115,12 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			expectOutput: wire.SNACMessage{
 			expectOutput: wire.SNACMessage{
@@ -131,7 +131,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 					TLVRestBlock: wire.TLVRestBlock{
 					TLVRestBlock: wire.TLVRestBlock{
 						TLVList: wire.TLVList{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+							wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 						},
 						},
@@ -150,7 +150,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -158,7 +158,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
@@ -170,12 +170,12 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			expectOutput: wire.SNACMessage{
 			expectOutput: wire.SNACMessage{
@@ -186,7 +186,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 					TLVRestBlock: wire.TLVRestBlock{
 					TLVRestBlock: wire.TLVRestBlock{
 						TLVList: wire.TLVList{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+							wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 						},
 						},
@@ -205,7 +205,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -213,7 +213,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
@@ -226,12 +226,12 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			expectOutput: wire.SNACMessage{
 			expectOutput: wire.SNACMessage{
@@ -242,7 +242,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 					TLVRestBlock: wire.TLVRestBlock{
 					TLVRestBlock: wire.TLVRestBlock{
 						TLVList: wire.TLVList{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+							wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 							wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 						},
 						},
@@ -259,7 +259,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -267,13 +267,13 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, io.EOF
 				return user, io.EOF
 			},
 			},
 			wantErr: io.EOF,
 			wantErr: io.EOF,
@@ -287,7 +287,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-password-hash")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -295,7 +295,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
@@ -307,7 +307,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			wantErr: io.EOF,
 			wantErr: io.EOF,
@@ -322,7 +322,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad_password")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad_password")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -330,7 +330,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     nil,
 							result:     nil,
 						},
 						},
 					},
 					},
@@ -344,7 +344,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 				Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{
 					TLVRestBlock: wire.TLVRestBlock{
 					TLVRestBlock: wire.TLVRestBlock{
 						TLVList: wire.TLVList{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+							wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 							wire.NewTLV(wire.LoginTLVTagsErrorSubcode, uint16(0x01)),
 							wire.NewTLV(wire.LoginTLVTagsErrorSubcode, uint16(0x01)),
 						},
 						},
 					},
 					},
@@ -357,7 +357,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -365,7 +365,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							err:        io.EOF,
 							err:        io.EOF,
 						},
 						},
 					},
 					},
@@ -411,8 +411,8 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 
 
 func TestAuthService_FLAPLoginResponse(t *testing.T) {
 func TestAuthService_FLAPLoginResponse(t *testing.T) {
 	user := state.User{
 	user := state.User{
-		ScreenName: "screen_name",
-		AuthKey:    "auth_key",
+		IdentScreenName: state.NewIdentScreenName("screen_name"),
+		AuthKey:         "auth_key",
 	}
 	}
 	assert.NoError(t, user.HashPassword("the_password"))
 	assert.NoError(t, user.HashPassword("the_password"))
 
 
@@ -430,7 +430,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 		// method's dependencies
 		// method's dependencies
 		mockParams mockParams
 		mockParams mockParams
 		// newUserFn is the function that registers a new user account
 		// newUserFn is the function that registers a new user account
-		newUserFn func(screenName string) (state.User, error)
+		newUserFn func(screenName state.DisplayScreenName) (state.User, error)
 		// expectOutput is the response sent from the server to client
 		// expectOutput is the response sent from the server to client
 		expectOutput wire.TLVRestBlock
 		expectOutput wire.TLVRestBlock
 		// wantErr is the error we expect from the method
 		// wantErr is the error we expect from the method
@@ -446,7 +446,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsRoastedPassword, roastedPassword),
 						wire.NewTLV(wire.LoginTLVTagsRoastedPassword, roastedPassword),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -454,21 +454,21 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
 			expectOutput: wire.TLVRestBlock{
 			expectOutput: wire.TLVRestBlock{
 				TLVList: wire.TLVList{
 				TLVList: wire.TLVList{
-					wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+					wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 				},
 				},
@@ -485,7 +485,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsRoastedPassword, roastedPassword),
 						wire.NewTLV(wire.LoginTLVTagsRoastedPassword, roastedPassword),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -493,7 +493,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     nil,
 							result:     nil,
 						},
 						},
 					},
 					},
@@ -505,17 +505,17 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			expectOutput: wire.TLVRestBlock{
 			expectOutput: wire.TLVRestBlock{
 				TLVList: wire.TLVList{
 				TLVList: wire.TLVList{
-					wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+					wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 				},
 				},
@@ -532,7 +532,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -540,7 +540,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
@@ -552,17 +552,17 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			expectOutput: wire.TLVRestBlock{
 			expectOutput: wire.TLVRestBlock{
 				TLVList: wire.TLVList{
 				TLVList: wire.TLVList{
-					wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+					wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 				},
 				},
@@ -579,7 +579,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -587,7 +587,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
@@ -600,17 +600,17 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				},
 				},
 				cookieIssuerParams: cookieIssuerParams{
 				cookieIssuerParams: cookieIssuerParams{
 					{
 					{
-						data:   []byte(user.ScreenName),
+						data:   []byte(user.IdentScreenName.String()),
 						cookie: []byte("the-cookie"),
 						cookie: []byte("the-cookie"),
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			expectOutput: wire.TLVRestBlock{
 			expectOutput: wire.TLVRestBlock{
 				TLVList: wire.TLVList{
 				TLVList: wire.TLVList{
-					wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+					wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsReconnectHere, "127.0.0.1:1234"),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 					wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, []byte("the-cookie")),
 				},
 				},
@@ -625,7 +625,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -633,13 +633,13 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, io.EOF
 				return user, io.EOF
 			},
 			},
 			wantErr: io.EOF,
 			wantErr: io.EOF,
@@ -653,7 +653,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -661,7 +661,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     &user,
 							result:     &user,
 						},
 						},
 					},
 					},
@@ -673,7 +673,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 					},
 					},
 				},
 				},
 			},
 			},
-			newUserFn: func(screenName string) (state.User, error) {
+			newUserFn: func(screenName state.DisplayScreenName) (state.User, error) {
 				return user, nil
 				return user, nil
 			},
 			},
 			wantErr: io.EOF,
 			wantErr: io.EOF,
@@ -688,7 +688,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, []byte("bad-roasted-password")),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -696,7 +696,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							result:     nil,
 							result:     nil,
 						},
 						},
 					},
 					},
@@ -704,7 +704,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 			},
 			},
 			expectOutput: wire.TLVRestBlock{
 			expectOutput: wire.TLVRestBlock{
 				TLVList: wire.TLVList{
 				TLVList: wire.TLVList{
-					wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+					wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					wire.NewTLV(wire.LoginTLVTagsErrorSubcode, uint16(0x01)),
 					wire.NewTLV(wire.LoginTLVTagsErrorSubcode, uint16(0x01)),
 				},
 				},
 			},
 			},
@@ -715,7 +715,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				TLVRestBlock: wire.TLVRestBlock{
 				TLVRestBlock: wire.TLVRestBlock{
 					TLVList: wire.TLVList{
 					TLVList: wire.TLVList{
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
 						wire.NewTLV(wire.LoginTLVTagsPasswordHash, user.StrongMD5Pass),
-						wire.NewTLV(wire.LoginTLVTagsScreenName, user.ScreenName),
+						wire.NewTLV(wire.LoginTLVTagsScreenName, user.IdentScreenName),
 					},
 					},
 				},
 				},
 			},
 			},
@@ -723,7 +723,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: user.ScreenName,
+							screenName: user.IdentScreenName,
 							err:        io.EOF,
 							err:        io.EOF,
 						},
 						},
 					},
 					},
@@ -800,10 +800,10 @@ func TestAuthService_BUCPChallengeRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: "sn_user_a",
+							screenName: state.NewIdentScreenName("sn_user_a"),
 							result: &state.User{
 							result: &state.User{
-								ScreenName: "sn_user_a",
-								AuthKey:    "auth_key_user_a",
+								IdentScreenName: state.NewIdentScreenName("sn_user_a"),
+								AuthKey:         "auth_key_user_a",
 							},
 							},
 						},
 						},
 					},
 					},
@@ -837,7 +837,7 @@ func TestAuthService_BUCPChallengeRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: "sn_user_b",
+							screenName: state.NewIdentScreenName("sn_user_b"),
 							result:     nil,
 							result:     nil,
 						},
 						},
 					},
 					},
@@ -870,7 +870,7 @@ func TestAuthService_BUCPChallengeRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: "sn_user_b",
+							screenName: state.NewIdentScreenName("sn_user_b"),
 							result:     nil,
 							result:     nil,
 						},
 						},
 					},
 					},
@@ -903,7 +903,7 @@ func TestAuthService_BUCPChallengeRequest(t *testing.T) {
 				userManagerParams: userManagerParams{
 				userManagerParams: userManagerParams{
 					getUserParams: getUserParams{
 					getUserParams: getUserParams{
 						{
 						{
-							screenName: "sn_user_b",
+							screenName: state.NewIdentScreenName("sn_user_b"),
 							err:        io.EOF,
 							err:        io.EOF,
 						},
 						},
 					},
 					},
@@ -941,16 +941,23 @@ func TestAuthService_RegisterChatSession_HappyPath(t *testing.T) {
 
 
 	c := chatLoginCookie{
 	c := chatLoginCookie{
 		ChatCookie: cookie,
 		ChatCookie: cookie,
-		ScreenName: sess.ScreenName(),
+		ScreenName: sess.IdentScreenName().String(),
 	}
 	}
 	buf := &bytes.Buffer{}
 	buf := &bytes.Buffer{}
 	assert.NoError(t, wire.Marshal(c, buf))
 	assert.NoError(t, wire.Marshal(c, buf))
 
 
 	sessionManager := newMockSessionManager(t)
 	sessionManager := newMockSessionManager(t)
 	sessionManager.EXPECT().
 	sessionManager.EXPECT().
-		AddSession(sess.ScreenName()).
+		AddSession(sess.DisplayScreenName()).
 		Return(sess)
 		Return(sess)
 
 
+	userManager := newMockUserManager(t)
+	userManager.EXPECT().
+		User(sess.IdentScreenName()).
+		Return(&state.User{
+			DisplayScreenName: sess.DisplayScreenName(),
+		}, nil)
+
 	chatRegistry := newMockChatRegistry(t)
 	chatRegistry := newMockChatRegistry(t)
 	chatRegistry.EXPECT().
 	chatRegistry.EXPECT().
 		Retrieve(cookie).
 		Retrieve(cookie).
@@ -958,7 +965,7 @@ func TestAuthService_RegisterChatSession_HappyPath(t *testing.T) {
 
 
 	cookieIssuer := newMockCookieIssuer(t)
 	cookieIssuer := newMockCookieIssuer(t)
 
 
-	svc := NewAuthService(config.Config{}, nil, nil, chatRegistry, nil, cookieIssuer, nil)
+	svc := NewAuthService(config.Config{}, nil, userManager, chatRegistry, nil, cookieIssuer, nil)
 
 
 	have, err := svc.RegisterChatSession(buf.Bytes())
 	have, err := svc.RegisterChatSession(buf.Bytes())
 	assert.NoError(t, err)
 	assert.NoError(t, err)
@@ -971,7 +978,7 @@ func TestAuthService_RegisterBOSSession_ChatNotFound(t *testing.T) {
 
 
 	c := chatLoginCookie{
 	c := chatLoginCookie{
 		ChatCookie: cookie,
 		ChatCookie: cookie,
-		ScreenName: sess.ScreenName(),
+		ScreenName: sess.IdentScreenName().String(),
 	}
 	}
 	loginCookie := &bytes.Buffer{}
 	loginCookie := &bytes.Buffer{}
 	assert.NoError(t, wire.Marshal(c, loginCookie))
 	assert.NoError(t, wire.Marshal(c, loginCookie))
@@ -993,14 +1000,19 @@ func TestAuthService_RegisterBOSSession_HappyPath(t *testing.T) {
 
 
 	sessionManager := newMockSessionManager(t)
 	sessionManager := newMockSessionManager(t)
 	sessionManager.EXPECT().
 	sessionManager.EXPECT().
-		AddSession(sess.ScreenName()).
+		AddSession(sess.DisplayScreenName()).
 		Return(sess)
 		Return(sess)
 
 
 	cookieIssuer := newMockCookieIssuer(t)
 	cookieIssuer := newMockCookieIssuer(t)
 
 
-	svc := NewAuthService(config.Config{}, sessionManager, nil, nil, nil, cookieIssuer, nil)
+	userManager := newMockUserManager(t)
+	userManager.EXPECT().
+		User(sess.IdentScreenName()).
+		Return(&state.User{DisplayScreenName: sess.DisplayScreenName()}, nil)
 
 
-	have, err := svc.RegisterBOSSession(sess.ScreenName())
+	svc := NewAuthService(config.Config{}, sessionManager, userManager, nil, nil, cookieIssuer, nil)
+
+	have, err := svc.RegisterBOSSession(sess.IdentScreenName())
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	assert.Equal(t, sess, have)
 	assert.Equal(t, sess, have)
 }
 }
@@ -1010,14 +1022,19 @@ func TestAuthService_RegisterBOSSession_SessionNotFound(t *testing.T) {
 
 
 	sessionManager := newMockSessionManager(t)
 	sessionManager := newMockSessionManager(t)
 	sessionManager.EXPECT().
 	sessionManager.EXPECT().
-		AddSession(sess.ScreenName()).
+		AddSession(sess.DisplayScreenName()).
 		Return(nil)
 		Return(nil)
 
 
 	cookieIssuer := newMockCookieIssuer(t)
 	cookieIssuer := newMockCookieIssuer(t)
 
 
-	svc := NewAuthService(config.Config{}, sessionManager, nil, nil, nil, cookieIssuer, nil)
+	userManager := newMockUserManager(t)
+	userManager.EXPECT().
+		User(sess.IdentScreenName()).
+		Return(&state.User{DisplayScreenName: sess.DisplayScreenName()}, nil)
+
+	svc := NewAuthService(config.Config{}, sessionManager, userManager, nil, nil, cookieIssuer, nil)
 
 
-	have, err := svc.RegisterBOSSession(sess.ScreenName())
+	have, err := svc.RegisterBOSSession(sess.IdentScreenName())
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	assert.Nil(t, have)
 	assert.Nil(t, have)
 }
 }
@@ -1193,14 +1210,14 @@ func TestAuthService_Signout(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					deleteUserParams: deleteUserParams{
 					deleteUserParams: deleteUserParams{
 						{
 						{
-							userScreenName: "user_screen_name",
+							userScreenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1222,7 +1239,7 @@ func TestAuthService_Signout(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyDeparted(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyDeparted(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}

+ 2 - 2
foodgroup/bart_test.go

@@ -49,7 +49,7 @@ func TestBARTService_UpsertItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -87,7 +87,7 @@ func TestBARTService_UpsertItem(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}

+ 12 - 12
foodgroup/buddy.go

@@ -57,13 +57,13 @@ func (s BuddyService) RightsQuery(_ context.Context, frameIn wire.SNACFrame) wir
 
 
 func (s BuddyService) AddBuddies(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x04_BuddyAddBuddies) error {
 func (s BuddyService) AddBuddies(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x04_BuddyAddBuddies) error {
 	for _, entry := range inBody.Buddies {
 	for _, entry := range inBody.Buddies {
-		s.legacyBuddyListManager.AddBuddy(sess.ScreenName(), entry.ScreenName)
+		s.legacyBuddyListManager.AddBuddy(sess.IdentScreenName(), state.NewIdentScreenName(entry.ScreenName))
 		if !sess.SignonComplete() {
 		if !sess.SignonComplete() {
 			// client has not completed sign-on sequence, so any arrival
 			// client has not completed sign-on sequence, so any arrival
 			// messages sent at this point would be ignored by the client.
 			// messages sent at this point would be ignored by the client.
 			continue
 			continue
 		}
 		}
-		buddy := s.messageRelayer.RetrieveByScreenName(entry.ScreenName)
+		buddy := s.messageRelayer.RetrieveByScreenName(state.NewIdentScreenName(entry.ScreenName))
 		if buddy == nil || buddy.Invisible() {
 		if buddy == nil || buddy.Invisible() {
 			continue
 			continue
 		}
 		}
@@ -77,7 +77,7 @@ func (s BuddyService) AddBuddies(ctx context.Context, sess *state.Session, inBod
 
 
 func (s BuddyService) DelBuddies(_ context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) {
 func (s BuddyService) DelBuddies(_ context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) {
 	for _, entry := range inBody.Buddies {
 	for _, entry := range inBody.Buddies {
-		s.legacyBuddyListManager.DeleteBuddy(sess.ScreenName(), entry.ScreenName)
+		s.legacyBuddyListManager.DeleteBuddy(sess.IdentScreenName(), state.NewIdentScreenName(entry.ScreenName))
 	}
 	}
 }
 }
 
 
@@ -94,7 +94,7 @@ func (s BuddyService) UnicastBuddyArrived(ctx context.Context, from *state.Sessi
 	case icon != nil:
 	case icon != nil:
 		userInfo.Append(wire.NewTLV(wire.OServiceUserInfoBARTInfo, *icon))
 		userInfo.Append(wire.NewTLV(wire.OServiceUserInfoBARTInfo, *icon))
 	}
 	}
-	s.messageRelayer.RelayToScreenName(ctx, to.ScreenName(), wire.SNACMessage{
+	s.messageRelayer.RelayToScreenName(ctx, to.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Buddy,
 			FoodGroup: wire.Buddy,
 			SubGroup:  wire.BuddyArrived,
 			SubGroup:  wire.BuddyArrived,
@@ -112,13 +112,13 @@ func (s BuddyService) UnicastBuddyArrived(ctx context.Context, from *state.Sessi
 // buddy icons, warning levels, invisibility status, etc.
 // buddy icons, warning levels, invisibility status, etc.
 func (s BuddyService) BroadcastBuddyArrived(ctx context.Context, sess *state.Session) error {
 func (s BuddyService) BroadcastBuddyArrived(ctx context.Context, sess *state.Session) error {
 	// find users who have this user on their server-side buddy list
 	// find users who have this user on their server-side buddy list
-	recipients, err := s.feedbagManager.AdjacentUsers(sess.ScreenName())
+	recipients, err := s.feedbagManager.AdjacentUsers(sess.IdentScreenName())
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// find users who have this user on their client-side buddy list
 	// find users who have this user on their client-side buddy list
-	legacyUsers := s.legacyBuddyListManager.WhoAddedUser(sess.ScreenName())
+	legacyUsers := s.legacyBuddyListManager.WhoAddedUser(sess.IdentScreenName())
 	recipients = append(recipients, legacyUsers...)
 	recipients = append(recipients, legacyUsers...)
 
 
 	userInfo := sess.TLVUserInfo()
 	userInfo := sess.TLVUserInfo()
@@ -147,7 +147,7 @@ func (s BuddyService) BroadcastBuddyArrived(ctx context.Context, sess *state.Ses
 // from their feedbag. If it exists, the buddy icon is the feedbag item of
 // from their feedbag. If it exists, the buddy icon is the feedbag item of
 // class wire.FeedbagClassIdBart with BART type wire.BARTTypesBuddyIcon.
 // class wire.FeedbagClassIdBart with BART type wire.BARTTypesBuddyIcon.
 func getBuddyIconRefFromFeedbag(sess *state.Session, feedbagManager FeedbagManager) (*wire.BARTID, error) {
 func getBuddyIconRefFromFeedbag(sess *state.Session, feedbagManager FeedbagManager) (*wire.BARTID, error) {
-	items, err := feedbagManager.Feedbag(sess.ScreenName())
+	items, err := feedbagManager.Feedbag(sess.IdentScreenName())
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -198,12 +198,12 @@ func extractBARTItemType(item wire.FeedbagItem) (uint16, error) {
 }
 }
 
 
 func (s BuddyService) BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error {
 func (s BuddyService) BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error {
-	recipients, err := s.feedbagManager.AdjacentUsers(sess.ScreenName())
+	recipients, err := s.feedbagManager.AdjacentUsers(sess.IdentScreenName())
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	legacyUsers := s.legacyBuddyListManager.WhoAddedUser(sess.ScreenName())
+	legacyUsers := s.legacyBuddyListManager.WhoAddedUser(sess.IdentScreenName())
 	recipients = append(recipients, legacyUsers...)
 	recipients = append(recipients, legacyUsers...)
 
 
 	s.messageRelayer.RelayToScreenNames(ctx, recipients, wire.SNACMessage{
 	s.messageRelayer.RelayToScreenNames(ctx, recipients, wire.SNACMessage{
@@ -215,7 +215,7 @@ func (s BuddyService) BroadcastBuddyDeparted(ctx context.Context, sess *state.Se
 			TLVUserInfo: wire.TLVUserInfo{
 			TLVUserInfo: wire.TLVUserInfo{
 				// don't include the TLV block, otherwise the AIM client fails
 				// don't include the TLV block, otherwise the AIM client fails
 				// to process the block event
 				// to process the block event
-				ScreenName:   sess.ScreenName(),
+				ScreenName:   string(sess.DisplayScreenName()),
 				WarningLevel: sess.Warning(),
 				WarningLevel: sess.Warning(),
 			},
 			},
 		},
 		},
@@ -225,7 +225,7 @@ func (s BuddyService) BroadcastBuddyDeparted(ctx context.Context, sess *state.Se
 }
 }
 
 
 func (s BuddyService) UnicastBuddyDeparted(ctx context.Context, from *state.Session, to *state.Session) {
 func (s BuddyService) UnicastBuddyDeparted(ctx context.Context, from *state.Session, to *state.Session) {
-	s.messageRelayer.RelayToScreenName(ctx, to.ScreenName(), wire.SNACMessage{
+	s.messageRelayer.RelayToScreenName(ctx, to.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Buddy,
 			FoodGroup: wire.Buddy,
 			SubGroup:  wire.BuddyDeparted,
 			SubGroup:  wire.BuddyDeparted,
@@ -234,7 +234,7 @@ func (s BuddyService) UnicastBuddyDeparted(ctx context.Context, from *state.Sess
 			TLVUserInfo: wire.TLVUserInfo{
 			TLVUserInfo: wire.TLVUserInfo{
 				// don't include the TLV block, otherwise the AIM client fails
 				// don't include the TLV block, otherwise the AIM client fails
 				// to process the block event
 				// to process the block event
-				ScreenName:   from.ScreenName(),
+				ScreenName:   string(from.DisplayScreenName()),
 				WarningLevel: from.Warning(),
 				WarningLevel: from.Warning(),
 			},
 			},
 		},
 		},

+ 44 - 38
foodgroup/buddy_test.go

@@ -70,29 +70,29 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					addBuddyParams: addBuddyParams{
 					addBuddyParams: addBuddyParams{
 						{
 						{
-							userScreenName:  "user_screen_name",
-							buddyScreenName: "buddy_1_online",
+							userScreenName:  state.NewIdentScreenName("user_screen_name"),
+							buddyScreenName: state.NewIdentScreenName("buddy_1_online"),
 						},
 						},
 						{
 						{
-							userScreenName:  "user_screen_name",
-							buddyScreenName: "buddy_2_offline",
+							userScreenName:  state.NewIdentScreenName("user_screen_name"),
+							buddyScreenName: state.NewIdentScreenName("buddy_2_offline"),
 						},
 						},
 					},
 					},
 				},
 				},
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_1_online",
+							screenName: state.NewIdentScreenName("buddy_1_online"),
 							sess:       newTestSession("buddy_1_online", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy_1_online", sessOptCannedSignonTime),
 						},
 						},
 						{
 						{
-							screenName: "buddy_2_offline",
+							screenName: state.NewIdentScreenName("buddy_2_offline"),
 							sess:       nil,
 							sess:       nil,
 						},
 						},
 					},
 					},
 					relayToScreenNameParams: relayToScreenNameParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,
@@ -108,7 +108,7 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "buddy_1_online",
+							screenName: state.NewIdentScreenName("buddy_1_online"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -133,12 +133,12 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					addBuddyParams: addBuddyParams{
 					addBuddyParams: addBuddyParams{
 						{
 						{
-							userScreenName:  "user_screen_name",
-							buddyScreenName: "buddy_1_online",
+							userScreenName:  state.NewIdentScreenName("user_screen_name"),
+							buddyScreenName: state.NewIdentScreenName("buddy_1_online"),
 						},
 						},
 						{
 						{
-							userScreenName:  "user_screen_name",
-							buddyScreenName: "buddy_2_offline",
+							userScreenName:  state.NewIdentScreenName("user_screen_name"),
+							buddyScreenName: state.NewIdentScreenName("buddy_2_offline"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -212,12 +212,12 @@ func TestBuddyService_DelBuddies(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					deleteBuddyParams: deleteBuddyParams{
 					deleteBuddyParams: deleteBuddyParams{
 						{
 						{
-							userScreenName:  "user_screen_name",
-							buddyScreenName: "buddy_1_online",
+							userScreenName:  state.NewIdentScreenName("user_screen_name"),
+							buddyScreenName: state.NewIdentScreenName("buddy_1_online"),
 						},
 						},
 						{
 						{
-							userScreenName:  "user_screen_name",
-							buddyScreenName: "buddy_2_offline",
+							userScreenName:  state.NewIdentScreenName("user_screen_name"),
+							buddyScreenName: state.NewIdentScreenName("buddy_2_offline"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -256,13 +256,13 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					adjacentUsersParams: adjacentUsersParams{
 					adjacentUsersParams: adjacentUsersParams{
 						{
 						{
-							screenName: "user_screen_name",
-							users:      []string{"friend1"},
+							screenName: state.NewIdentScreenName("user_screen_name"),
+							users:      []state.IdentScreenName{state.NewIdentScreenName("friend1")},
 						},
 						},
 					},
 					},
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results:    []wire.FeedbagItem{},
 							results:    []wire.FeedbagItem{},
 						},
 						},
 					},
 					},
@@ -270,7 +270,10 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
 						{
 						{
-							screenNames: []string{"friend1", "friend2"},
+							screenNames: []state.IdentScreenName{
+								state.NewIdentScreenName("friend1"),
+								state.NewIdentScreenName("friend2"),
+							},
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,
@@ -286,8 +289,8 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					whoAddedUserParams: whoAddedUserParams{
 					whoAddedUserParams: whoAddedUserParams{
 						{
 						{
-							userScreenName: "user_screen_name",
-							result:         []string{"friend2"},
+							userScreenName: state.NewIdentScreenName("user_screen_name"),
+							result:         []state.IdentScreenName{state.NewIdentScreenName("friend2")},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -300,13 +303,13 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					adjacentUsersParams: adjacentUsersParams{
 					adjacentUsersParams: adjacentUsersParams{
 						{
 						{
-							screenName: "user_screen_name",
-							users:      []string{"friend1"},
+							screenName: state.NewIdentScreenName("user_screen_name"),
+							users:      []state.IdentScreenName{state.NewIdentScreenName("friend1")},
 						},
 						},
 					},
 					},
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results: []wire.FeedbagItem{
 							results: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIdBuddy,
 									ClassID: wire.FeedbagClassIdBuddy,
@@ -334,7 +337,7 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
 						{
 						{
-							screenNames: []string{"friend1"},
+							screenNames: []state.IdentScreenName{state.NewIdentScreenName("friend1")},
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,
@@ -359,8 +362,8 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					whoAddedUserParams: whoAddedUserParams{
 					whoAddedUserParams: whoAddedUserParams{
 						{
 						{
-							userScreenName: "user_screen_name",
-							result:         []string{},
+							userScreenName: state.NewIdentScreenName("user_screen_name"),
+							result:         []state.IdentScreenName{},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -418,15 +421,18 @@ func TestBuddyService_BroadcastDeparture(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					adjacentUsersParams: adjacentUsersParams{
 					adjacentUsersParams: adjacentUsersParams{
 						{
 						{
-							screenName: "user_screen_name",
-							users:      []string{"friend1"},
+							screenName: state.NewIdentScreenName("user_screen_name"),
+							users:      []state.IdentScreenName{state.NewIdentScreenName("friend1")},
 						},
 						},
 					},
 					},
 				},
 				},
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
 						{
 						{
-							screenNames: []string{"friend1", "friend2"},
+							screenNames: []state.IdentScreenName{
+								state.NewIdentScreenName("friend1"),
+								state.NewIdentScreenName("friend2"),
+							},
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,
@@ -445,8 +451,8 @@ func TestBuddyService_BroadcastDeparture(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					whoAddedUserParams: whoAddedUserParams{
 					whoAddedUserParams: whoAddedUserParams{
 						{
 						{
-							userScreenName: "user_screen_name",
-							result:         []string{"friend2"},
+							userScreenName: state.NewIdentScreenName("user_screen_name"),
+							result:         []state.IdentScreenName{state.NewIdentScreenName("friend2")},
 						},
 						},
 					},
 					},
 				},
 				},
@@ -502,7 +508,7 @@ func TestBuddyService_UnicastBuddyDeparted(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
 						{
-							screenName: "dest_screen_name",
+							screenName: state.NewIdentScreenName("dest_screen_name"),
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,
@@ -557,7 +563,7 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "src_screen_name",
+							screenName: state.NewIdentScreenName("src_screen_name"),
 							results:    []wire.FeedbagItem{},
 							results:    []wire.FeedbagItem{},
 						},
 						},
 					},
 					},
@@ -565,7 +571,7 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
 						{
-							screenName: "dest_screen_name",
+							screenName: state.NewIdentScreenName("dest_screen_name"),
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,
@@ -588,7 +594,7 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "src_screen_name",
+							screenName: state.NewIdentScreenName("src_screen_name"),
 							results: []wire.FeedbagItem{
 							results: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIdBuddy,
 									ClassID: wire.FeedbagClassIdBuddy,
@@ -616,7 +622,7 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
 						{
-							screenName: "dest_screen_name",
+							screenName: state.NewIdentScreenName("dest_screen_name"),
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.Buddy,
 									FoodGroup: wire.Buddy,

+ 2 - 2
foodgroup/chat.go

@@ -81,7 +81,7 @@ func setOnlineChatUsers(ctx context.Context, sess *state.Session, chatMessageRel
 		snacPayloadOut.Users = append(snacPayloadOut.Users, uSess.TLVUserInfo())
 		snacPayloadOut.Users = append(snacPayloadOut.Users, uSess.TLVUserInfo())
 	}
 	}
 
 
-	chatMessageRelayer.RelayToScreenName(ctx, sess.ScreenName(), wire.SNACMessage{
+	chatMessageRelayer.RelayToScreenName(ctx, sess.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Chat,
 			FoodGroup: wire.Chat,
 			SubGroup:  wire.ChatUsersJoined,
 			SubGroup:  wire.ChatUsersJoined,
@@ -119,7 +119,7 @@ func alertUserLeft(ctx context.Context, sess *state.Session, chatMessageRelayer
 }
 }
 
 
 func sendChatRoomInfoUpdate(ctx context.Context, sess *state.Session, chatMessageRelayer ChatMessageRelayer, room state.ChatRoom) {
 func sendChatRoomInfoUpdate(ctx context.Context, sess *state.Session, chatMessageRelayer ChatMessageRelayer, room state.ChatRoom) {
-	chatMessageRelayer.RelayToScreenName(ctx, sess.ScreenName(), wire.SNACMessage{
+	chatMessageRelayer.RelayToScreenName(ctx, sess.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Chat,
 			FoodGroup: wire.Chat,
 			SubGroup:  wire.ChatRoomInfoUpdate,
 			SubGroup:  wire.ChatRoomInfoUpdate,

+ 1 - 1
foodgroup/chat_nav.go

@@ -87,7 +87,7 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 	s.chatRegistry.Register(room, chatSessMgr)
 	s.chatRegistry.Register(room, chatSessMgr)
 
 
 	// add user to chat room
 	// add user to chat room
-	chatSess := chatSessMgr.AddSession(sess.ScreenName())
+	chatSess := chatSessMgr.AddSession(sess.DisplayScreenName())
 	chatSess.SetChatRoomCookie(room.Cookie)
 	chatSess.SetChatRoomCookie(room.Cookie)
 
 
 	return wire.SNACMessage{
 	return wire.SNACMessage{

+ 2 - 1
foodgroup/chat_nav_test.go

@@ -18,7 +18,8 @@ func TestChatNavService_CreateRoom(t *testing.T) {
 	chatRegistry := state.NewChatRegistry()
 	chatRegistry := state.NewChatRegistry()
 
 
 	sessionManager := newMockSessionManager(t)
 	sessionManager := newMockSessionManager(t)
-	sessionManager.EXPECT().AddSession(bosSess.ScreenName()).
+	sessionManager.EXPECT().
+		AddSession(bosSess.DisplayScreenName()).
 		Return(chatSess)
 		Return(chatSess)
 
 
 	newChatRoom := func() state.ChatRoom {
 	newChatRoom := func() state.ChatRoom {

+ 12 - 12
foodgroup/feedbag.go

@@ -91,7 +91,7 @@ func (s FeedbagService) RightsQuery(_ context.Context, inFrame wire.SNACFrame) w
 // Query fetches the user's feedbag (aka buddy list). It returns
 // Query fetches the user's feedbag (aka buddy list). It returns
 // wire.FeedbagReply, which contains feedbag entries.
 // wire.FeedbagReply, which contains feedbag entries.
 func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wire.SNACFrame) (wire.SNACMessage, error) {
 func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wire.SNACFrame) (wire.SNACMessage, error) {
-	fb, err := s.feedbagManager.Feedbag(sess.ScreenName())
+	fb, err := s.feedbagManager.Feedbag(sess.IdentScreenName())
 	if err != nil {
 	if err != nil {
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
 	}
 	}
@@ -99,7 +99,7 @@ func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wi
 	lm := time.UnixMilli(0)
 	lm := time.UnixMilli(0)
 
 
 	if len(fb) > 0 {
 	if len(fb) > 0 {
-		lm, err = s.feedbagManager.FeedbagLastModified(sess.ScreenName())
+		lm, err = s.feedbagManager.FeedbagLastModified(sess.IdentScreenName())
 		if err != nil {
 		if err != nil {
 			return wire.SNACMessage{}, err
 			return wire.SNACMessage{}, err
 		}
 		}
@@ -124,7 +124,7 @@ func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wi
 // inBody.LastUpdate, else return wire.FeedbagReply, which contains feedbag
 // inBody.LastUpdate, else return wire.FeedbagReply, which contains feedbag
 // entries.
 // entries.
 func (s FeedbagService) QueryIfModified(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x05_FeedbagQueryIfModified) (wire.SNACMessage, error) {
 func (s FeedbagService) QueryIfModified(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x05_FeedbagQueryIfModified) (wire.SNACMessage, error) {
-	fb, err := s.feedbagManager.Feedbag(sess.ScreenName())
+	fb, err := s.feedbagManager.Feedbag(sess.IdentScreenName())
 	if err != nil {
 	if err != nil {
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
 	}
 	}
@@ -132,7 +132,7 @@ func (s FeedbagService) QueryIfModified(_ context.Context, sess *state.Session,
 	lm := time.UnixMilli(0)
 	lm := time.UnixMilli(0)
 
 
 	if len(fb) > 0 {
 	if len(fb) > 0 {
-		lm, err = s.feedbagManager.FeedbagLastModified(sess.ScreenName())
+		lm, err = s.feedbagManager.FeedbagLastModified(sess.IdentScreenName())
 		if err != nil {
 		if err != nil {
 			return wire.SNACMessage{}, err
 			return wire.SNACMessage{}, err
 		}
 		}
@@ -177,7 +177,7 @@ func (s FeedbagService) UpsertItem(ctx context.Context, sess *state.Session, inF
 	for _, item := range items {
 	for _, item := range items {
 		// don't let users block themselves, it causes the AIM client to go
 		// don't let users block themselves, it causes the AIM client to go
 		// into a weird state.
 		// into a weird state.
-		if item.ClassID == 3 && item.Name == sess.ScreenName() {
+		if item.ClassID == 3 && state.NewIdentScreenName(item.Name) == sess.IdentScreenName() {
 			return wire.SNACMessage{
 			return wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					FoodGroup: wire.Feedbag,
 					FoodGroup: wire.Feedbag,
@@ -191,14 +191,14 @@ func (s FeedbagService) UpsertItem(ctx context.Context, sess *state.Session, inF
 		}
 		}
 	}
 	}
 
 
-	if err := s.feedbagManager.FeedbagUpsert(sess.ScreenName(), items); err != nil {
+	if err := s.feedbagManager.FeedbagUpsert(sess.IdentScreenName(), items); err != nil {
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
 	}
 	}
 
 
 	for _, item := range items {
 	for _, item := range items {
 		switch item.ClassID {
 		switch item.ClassID {
 		case wire.FeedbagClassIdBuddy, wire.FeedbagClassIDPermit: // add new buddy
 		case wire.FeedbagClassIdBuddy, wire.FeedbagClassIDPermit: // add new buddy
-			buddy := s.messageRelayer.RetrieveByScreenName(item.Name)
+			buddy := s.messageRelayer.RetrieveByScreenName(state.NewIdentScreenName(item.Name))
 			if buddy == nil || buddy.Invisible() {
 			if buddy == nil || buddy.Invisible() {
 				continue
 				continue
 			}
 			}
@@ -209,7 +209,7 @@ func (s FeedbagService) UpsertItem(ctx context.Context, sess *state.Session, inF
 			if sess.Invisible() {
 			if sess.Invisible() {
 				continue // user's offline, don't send departure notification
 				continue // user's offline, don't send departure notification
 			}
 			}
-			blockedSess := s.messageRelayer.RetrieveByScreenName(item.Name)
+			blockedSess := s.messageRelayer.RetrieveByScreenName(state.NewIdentScreenName(item.Name))
 			if blockedSess == nil {
 			if blockedSess == nil {
 				continue // blocked buddy is offline, nothing to do here
 				continue // blocked buddy is offline, nothing to do here
 			}
 			}
@@ -282,7 +282,7 @@ func (s FeedbagService) broadcastIconUpdate(ctx context.Context, sess *state.Ses
 		}
 		}
 	}
 	}
 
 
-	s.messageRelayer.RelayToScreenName(ctx, sess.ScreenName(), wire.SNACMessage{
+	s.messageRelayer.RelayToScreenName(ctx, sess.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.OService,
 			FoodGroup: wire.OService,
 			SubGroup:  wire.OServiceBartReply,
 			SubGroup:  wire.OServiceBartReply,
@@ -300,13 +300,13 @@ func (s FeedbagService) broadcastIconUpdate(ctx context.Context, sess *state.Ses
 // Sends buddy arrival notifications to each unblocked buddy if current user is
 // Sends buddy arrival notifications to each unblocked buddy if current user is
 // visible. It returns wire.FeedbagStatus, which contains update confirmation.
 // visible. It returns wire.FeedbagStatus, which contains update confirmation.
 func (s FeedbagService) DeleteItem(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x0A_FeedbagDeleteItem) (wire.SNACMessage, error) {
 func (s FeedbagService) DeleteItem(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x0A_FeedbagDeleteItem) (wire.SNACMessage, error) {
-	if err := s.feedbagManager.FeedbagDelete(sess.ScreenName(), inBody.Items); err != nil {
+	if err := s.feedbagManager.FeedbagDelete(sess.IdentScreenName(), inBody.Items); err != nil {
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
 	}
 	}
 
 
 	for _, item := range inBody.Items {
 	for _, item := range inBody.Items {
 		if item.ClassID == wire.FeedbagClassIDDeny {
 		if item.ClassID == wire.FeedbagClassIDDeny {
-			unblockedSess := s.messageRelayer.RetrieveByScreenName(item.Name)
+			unblockedSess := s.messageRelayer.RetrieveByScreenName(state.NewIdentScreenName(item.Name))
 			if unblockedSess == nil {
 			if unblockedSess == nil {
 				continue // unblocked user is offline, nothing to do here
 				continue // unblocked user is offline, nothing to do here
 			}
 			}
@@ -349,7 +349,7 @@ func (s FeedbagService) StartCluster(context.Context, wire.SNACFrame, wire.SNAC_
 // by AIM clients that use the feedbag food group for buddy list management (as
 // by AIM clients that use the feedbag food group for buddy list management (as
 // opposed to client-side management).
 // opposed to client-side management).
 func (s FeedbagService) Use(ctx context.Context, sess *state.Session) error {
 func (s FeedbagService) Use(ctx context.Context, sess *state.Session) error {
-	buddies, err := s.feedbagManager.Buddies(sess.ScreenName())
+	buddies, err := s.feedbagManager.Buddies(sess.IdentScreenName())
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 73 - 70
foodgroup/feedbag_test.go

@@ -38,7 +38,7 @@ func TestFeedbagService_Query(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results:    []wire.FeedbagItem{},
 							results:    []wire.FeedbagItem{},
 						},
 						},
 					},
 					},
@@ -68,7 +68,7 @@ func TestFeedbagService_Query(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results: []wire.FeedbagItem{
 							results: []wire.FeedbagItem{
 								{
 								{
 									Name: "buddy_1",
 									Name: "buddy_1",
@@ -81,7 +81,7 @@ func TestFeedbagService_Query(t *testing.T) {
 					},
 					},
 					feedbagLastModifiedParams: feedbagLastModifiedParams{
 					feedbagLastModifiedParams: feedbagLastModifiedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							result:     time.UnixMilli(1696472198082),
 							result:     time.UnixMilli(1696472198082),
 						},
 						},
 					},
 					},
@@ -162,7 +162,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results:    []wire.FeedbagItem{},
 							results:    []wire.FeedbagItem{},
 						},
 						},
 					},
 					},
@@ -194,7 +194,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results: []wire.FeedbagItem{
 							results: []wire.FeedbagItem{
 								{
 								{
 									Name: "buddy_1",
 									Name: "buddy_1",
@@ -207,7 +207,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 					},
 					},
 					feedbagLastModifiedParams: feedbagLastModifiedParams{
 					feedbagLastModifiedParams: feedbagLastModifiedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							result:     time.UnixMilli(200000),
 							result:     time.UnixMilli(200000),
 						},
 						},
 					},
 					},
@@ -248,7 +248,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagParams: feedbagParams{
 					feedbagParams: feedbagParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							results: []wire.FeedbagItem{
 							results: []wire.FeedbagItem{
 								{
 								{
 									Name: "buddy_1",
 									Name: "buddy_1",
@@ -261,7 +261,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 					},
 					},
 					feedbagLastModifiedParams: feedbagLastModifiedParams{
 					feedbagLastModifiedParams: feedbagLastModifiedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							result:     time.UnixMilli(100000),
 							result:     time.UnixMilli(100000),
 						},
 						},
 					},
 					},
@@ -406,7 +406,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDPermit,
 									ClassID: wire.FeedbagClassIDPermit,
@@ -423,11 +423,11 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_1_online",
+							screenName: state.NewIdentScreenName("buddy_1_online"),
 							sess:       newTestSession("buddy_1_online", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy_1_online", sessOptCannedSignonTime),
 						},
 						},
 						{
 						{
-							screenName: "buddy_2_online",
+							screenName: state.NewIdentScreenName("buddy_2_online"),
 							sess:       newTestSession("buddy_2_online", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy_2_online", sessOptCannedSignonTime),
 						},
 						},
 					},
 					},
@@ -435,12 +435,12 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 						{
 						{
-							from: "buddy_1_online",
-							to:   "user_screen_name",
+							from: state.NewIdentScreenName("buddy_1_online"),
+							to:   state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 						{
 						{
-							from: "buddy_2_online",
-							to:   "user_screen_name",
+							from: state.NewIdentScreenName("buddy_2_online"),
+							to:   state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -476,7 +476,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDPermit,
 									ClassID: wire.FeedbagClassIDPermit,
@@ -489,7 +489,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_offline",
+							screenName: state.NewIdentScreenName("buddy_offline"),
 							sess:       nil,
 							sess:       nil,
 						},
 						},
 					},
 					},
@@ -526,7 +526,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDPermit,
 									ClassID: wire.FeedbagClassIDPermit,
@@ -539,7 +539,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "invisible_buddy_online",
+							screenName: state.NewIdentScreenName("invisible_buddy_online"),
 							sess:       newTestSession("invisible_buddy_online", sessOptInvisible),
 							sess:       newTestSession("invisible_buddy_online", sessOptInvisible),
 						},
 						},
 					},
 					},
@@ -576,7 +576,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDDeny,
 									ClassID: wire.FeedbagClassIDDeny,
@@ -589,7 +589,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_1",
+							screenName: state.NewIdentScreenName("buddy_1"),
 							sess:       newTestSession("buddy_1"),
 							sess:       newTestSession("buddy_1"),
 						},
 						},
 					},
 					},
@@ -597,12 +597,12 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					unicastBuddyDepartedParams: unicastBuddyDepartedParams{
 					unicastBuddyDepartedParams: unicastBuddyDepartedParams{
 						{
 						{
-							from: "user_screen_name",
-							to:   "buddy_1",
+							from: state.NewIdentScreenName("user_screen_name"),
+							to:   state.NewIdentScreenName("buddy_1"),
 						},
 						},
 						{
 						{
-							from: "buddy_1",
-							to:   "user_screen_name",
+							from: state.NewIdentScreenName("buddy_1"),
+							to:   state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -638,7 +638,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDDeny,
 									ClassID: wire.FeedbagClassIDDeny,
@@ -651,7 +651,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_1",
+							screenName: state.NewIdentScreenName("buddy_1"),
 							sess:       nil,
 							sess:       nil,
 						},
 						},
 					},
 					},
@@ -688,7 +688,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDDeny,
 									ClassID: wire.FeedbagClassIDDeny,
@@ -771,7 +771,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIdBart,
 									ClassID: wire.FeedbagClassIdBart,
@@ -790,7 +790,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.OService,
 									FoodGroup: wire.OService,
@@ -855,7 +855,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIdBart,
 									ClassID: wire.FeedbagClassIdBart,
@@ -876,7 +876,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							message: wire.SNACMessage{
 							message: wire.SNACMessage{
 								Frame: wire.SNACFrame{
 								Frame: wire.SNACFrame{
 									FoodGroup: wire.OService,
 									FoodGroup: wire.OService,
@@ -898,7 +898,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -940,7 +940,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 					feedbagUpsertParams: feedbagUpsertParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIdBart,
 									ClassID: wire.FeedbagClassIdBart,
@@ -959,7 +959,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1021,7 +1021,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -1030,10 +1030,10 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					UnicastBuddyArrived(mock.Anything,
 					UnicastBuddyArrived(mock.Anything,
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.from
+							return s.IdentScreenName() == p.from
 						}),
 						}),
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.to
+							return s.IdentScreenName() == p.to
 						})).
 						})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -1042,10 +1042,10 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					UnicastBuddyDeparted(mock.Anything,
 					UnicastBuddyDeparted(mock.Anything,
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.from
+							return s.IdentScreenName() == p.from
 						}),
 						}),
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.to
+							return s.IdentScreenName() == p.to
 						}))
 						}))
 			}
 			}
 
 
@@ -1092,7 +1092,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIdBuddy,
 									ClassID: wire.FeedbagClassIdBuddy,
@@ -1138,7 +1138,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDDeny,
 									ClassID: wire.FeedbagClassIDDeny,
@@ -1155,11 +1155,11 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_1_online",
+							screenName: state.NewIdentScreenName("buddy_1_online"),
 							sess:       newTestSession("buddy_1_online", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy_1_online", sessOptCannedSignonTime),
 						},
 						},
 						{
 						{
-							screenName: "buddy_2_online",
+							screenName: state.NewIdentScreenName("buddy_2_online"),
 							sess:       newTestSession("buddy_2_online", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy_2_online", sessOptCannedSignonTime),
 						},
 						},
 					},
 					},
@@ -1167,20 +1167,20 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 						{
 						{
-							from: "buddy_1_online",
-							to:   "user_screen_name",
+							from: state.NewIdentScreenName("buddy_1_online"),
+							to:   state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 						{
 						{
-							from: "buddy_2_online",
-							to:   "user_screen_name",
+							from: state.NewIdentScreenName("buddy_2_online"),
+							to:   state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 						{
 						{
-							from: "user_screen_name",
-							to:   "buddy_1_online",
+							from: state.NewIdentScreenName("user_screen_name"),
+							to:   state.NewIdentScreenName("buddy_1_online"),
 						},
 						},
 						{
 						{
-							from: "user_screen_name",
-							to:   "buddy_2_online",
+							from: state.NewIdentScreenName("user_screen_name"),
+							to:   state.NewIdentScreenName("buddy_2_online"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1216,7 +1216,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDDeny,
 									ClassID: wire.FeedbagClassIDDeny,
@@ -1229,7 +1229,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy_offline",
+							screenName: state.NewIdentScreenName("buddy_offline"),
 							sess:       nil,
 							sess:       nil,
 						},
 						},
 					},
 					},
@@ -1266,7 +1266,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 					feedbagDeleteParams: feedbagDeleteParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 							items: []wire.FeedbagItem{
 							items: []wire.FeedbagItem{
 								{
 								{
 									ClassID: wire.FeedbagClassIDDeny,
 									ClassID: wire.FeedbagClassIDDeny,
@@ -1279,7 +1279,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "invisible_buddy_online",
+							screenName: state.NewIdentScreenName("invisible_buddy_online"),
 							sess:       newTestSession("invisible_buddy_online", sessOptInvisible),
 							sess:       newTestSession("invisible_buddy_online", sessOptInvisible),
 						},
 						},
 					},
 					},
@@ -1287,8 +1287,8 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 						{
 						{
-							from: "user_screen_name",
-							to:   "invisible_buddy_online",
+							from: state.NewIdentScreenName("user_screen_name"),
+							to:   state.NewIdentScreenName("invisible_buddy_online"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1326,10 +1326,10 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				buddyUpdateBroadcast.EXPECT().
 				buddyUpdateBroadcast.EXPECT().
 					UnicastBuddyArrived(mock.Anything,
 					UnicastBuddyArrived(mock.Anything,
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.from
+							return s.IdentScreenName() == p.from
 						}),
 						}),
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.to
+							return s.IdentScreenName() == p.to
 						})).
 						})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -1369,19 +1369,22 @@ func TestFeedbagService_Use(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					buddiesParams: buddiesParams{
 					buddiesParams: buddiesParams{
 						{
 						{
-							screenName: "test-user",
-							results:    []string{"buddy1", "buddy3"},
+							screenName: state.NewIdentScreenName("test-user"),
+							results: []state.IdentScreenName{
+								state.NewIdentScreenName("buddy1"),
+								state.NewIdentScreenName("buddy3"),
+							},
 						},
 						},
 					},
 					},
 				},
 				},
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy1",
+							screenName: state.NewIdentScreenName("buddy1"),
 							sess:       newTestSession("buddy1"),
 							sess:       newTestSession("buddy1"),
 						},
 						},
 						{
 						{
-							screenName: "buddy3",
+							screenName: state.NewIdentScreenName("buddy3"),
 							sess:       newTestSession("buddy3"),
 							sess:       newTestSession("buddy3"),
 						},
 						},
 					},
 					},
@@ -1389,12 +1392,12 @@ func TestFeedbagService_Use(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 						{
 						{
-							from: "buddy1",
-							to:   "test-user",
+							from: state.NewIdentScreenName("buddy1"),
+							to:   state.NewIdentScreenName("test-user"),
 						},
 						},
 						{
 						{
-							from: "buddy3",
-							to:   "test-user",
+							from: state.NewIdentScreenName("buddy3"),
+							to:   state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1421,10 +1424,10 @@ func TestFeedbagService_Use(t *testing.T) {
 				buddyUpdateBroadcast.EXPECT().
 				buddyUpdateBroadcast.EXPECT().
 					UnicastBuddyArrived(mock.Anything,
 					UnicastBuddyArrived(mock.Anything,
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.from
+							return s.IdentScreenName() == p.from
 						}),
 						}),
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.to
+							return s.IdentScreenName() == p.to
 						})).
 						})).
 					Return(nil)
 					Return(nil)
 			}
 			}

+ 14 - 12
foodgroup/icbm.go

@@ -58,7 +58,7 @@ func (s ICBMService) ParameterQuery(_ context.Context, inFrame wire.SNACFrame) w
 // the wire.ICBMChannelMsgToHost message contains a request acknowledgement
 // the wire.ICBMChannelMsgToHost message contains a request acknowledgement
 // flag.
 // flag.
 func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*wire.SNACMessage, error) {
 func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*wire.SNACMessage, error) {
-	blocked, err := s.feedbagManager.BlockedState(sess.ScreenName(), inBody.ScreenName)
+	blocked, err := s.feedbagManager.BlockedState(sess.IdentScreenName(), state.NewIdentScreenName(inBody.ScreenName))
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -80,7 +80,7 @@ func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session,
 		}, nil
 		}, nil
 	}
 	}
 
 
-	recipSess := s.messageRelayer.RetrieveByScreenName(inBody.ScreenName)
+	recipSess := s.messageRelayer.RetrieveByScreenName(state.NewIdentScreenName(inBody.ScreenName))
 	if recipSess == nil {
 	if recipSess == nil {
 		return &wire.SNACMessage{
 		return &wire.SNACMessage{
 			Frame: wire.SNACFrame{
 			Frame: wire.SNACFrame{
@@ -98,7 +98,7 @@ func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session,
 		Cookie:    inBody.Cookie,
 		Cookie:    inBody.Cookie,
 		ChannelID: inBody.ChannelID,
 		ChannelID: inBody.ChannelID,
 		TLVUserInfo: wire.TLVUserInfo{
 		TLVUserInfo: wire.TLVUserInfo{
-			ScreenName:   sess.ScreenName(),
+			ScreenName:   string(sess.DisplayScreenName()),
 			WarningLevel: sess.Warning(),
 			WarningLevel: sess.Warning(),
 		},
 		},
 		TLVRestBlock: wire.TLVRestBlock{
 		TLVRestBlock: wire.TLVRestBlock{
@@ -115,7 +115,7 @@ func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session,
 	// far as I can tell.
 	// far as I can tell.
 	clientIM.AppendList(inBody.TLVRestBlock.TLVList)
 	clientIM.AppendList(inBody.TLVRestBlock.TLVList)
 
 
-	s.messageRelayer.RelayToScreenName(ctx, recipSess.ScreenName(), wire.SNACMessage{
+	s.messageRelayer.RelayToScreenName(ctx, recipSess.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.ICBM,
 			FoodGroup: wire.ICBM,
 			SubGroup:  wire.ICBMChannelMsgToClient,
 			SubGroup:  wire.ICBMChannelMsgToClient,
@@ -146,7 +146,7 @@ func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session,
 // ClientEvent relays SNAC wire.ICBMClientEvent typing events from the
 // ClientEvent relays SNAC wire.ICBMClientEvent typing events from the
 // sender to the recipient.
 // sender to the recipient.
 func (s ICBMService) ClientEvent(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x14_ICBMClientEvent) error {
 func (s ICBMService) ClientEvent(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x14_ICBMClientEvent) error {
-	blocked, err := s.feedbagManager.BlockedState(sess.ScreenName(), inBody.ScreenName)
+	blocked, err := s.feedbagManager.BlockedState(sess.IdentScreenName(), state.NewIdentScreenName(inBody.ScreenName))
 
 
 	switch {
 	switch {
 	case err != nil:
 	case err != nil:
@@ -154,7 +154,7 @@ func (s ICBMService) ClientEvent(ctx context.Context, sess *state.Session, inFra
 	case blocked != state.BlockedNo:
 	case blocked != state.BlockedNo:
 		return nil
 		return nil
 	default:
 	default:
-		s.messageRelayer.RelayToScreenName(ctx, inBody.ScreenName, wire.SNACMessage{
+		s.messageRelayer.RelayToScreenName(ctx, state.NewIdentScreenName(inBody.ScreenName), wire.SNACMessage{
 			Frame: wire.SNACFrame{
 			Frame: wire.SNACFrame{
 				FoodGroup: wire.ICBM,
 				FoodGroup: wire.ICBM,
 				SubGroup:  wire.ICBMClientEvent,
 				SubGroup:  wire.ICBMClientEvent,
@@ -163,7 +163,7 @@ func (s ICBMService) ClientEvent(ctx context.Context, sess *state.Session, inFra
 			Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
 			Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
 				Cookie:     inBody.Cookie,
 				Cookie:     inBody.Cookie,
 				ChannelID:  inBody.ChannelID,
 				ChannelID:  inBody.ChannelID,
-				ScreenName: sess.ScreenName(),
+				ScreenName: string(sess.DisplayScreenName()),
 				Event:      inBody.Event,
 				Event:      inBody.Event,
 			},
 			},
 		})
 		})
@@ -179,9 +179,11 @@ func (s ICBMService) ClientEvent(ctx context.Context, sess *state.Session, inFra
 // warning was sent. Users may not warn themselves or warn users they have
 // warning was sent. Users may not warn themselves or warn users they have
 // blocked or are blocked by.
 // blocked or are blocked by.
 func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x08_ICBMEvilRequest) (wire.SNACMessage, error) {
 func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x08_ICBMEvilRequest) (wire.SNACMessage, error) {
+	identScreenName := state.NewIdentScreenName(inBody.ScreenName)
+
 	// don't let users warn themselves, it causes the AIM client to go into a
 	// don't let users warn themselves, it causes the AIM client to go into a
 	// weird state.
 	// weird state.
-	if inBody.ScreenName == sess.ScreenName() {
+	if identScreenName == sess.IdentScreenName() {
 		return wire.SNACMessage{
 		return wire.SNACMessage{
 			Frame: wire.SNACFrame{
 			Frame: wire.SNACFrame{
 				FoodGroup: wire.ICBM,
 				FoodGroup: wire.ICBM,
@@ -194,7 +196,7 @@ func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFra
 		}, nil
 		}, nil
 	}
 	}
 
 
-	blocked, err := s.feedbagManager.BlockedState(sess.ScreenName(), inBody.ScreenName)
+	blocked, err := s.feedbagManager.BlockedState(sess.IdentScreenName(), identScreenName)
 	if err != nil {
 	if err != nil {
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
 	}
 	}
@@ -211,7 +213,7 @@ func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFra
 		}, nil
 		}, nil
 	}
 	}
 
 
-	recipSess := s.messageRelayer.RetrieveByScreenName(inBody.ScreenName)
+	recipSess := s.messageRelayer.RetrieveByScreenName(identScreenName)
 	if recipSess == nil {
 	if recipSess == nil {
 		return wire.SNACMessage{
 		return wire.SNACMessage{
 			Frame: wire.SNACFrame{
 			Frame: wire.SNACFrame{
@@ -236,7 +238,7 @@ func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFra
 		notif = wire.SNAC_0x01_0x10_OServiceEvilNotification{
 		notif = wire.SNAC_0x01_0x10_OServiceEvilNotification{
 			NewEvil: recipSess.Warning(),
 			NewEvil: recipSess.Warning(),
 			TLVUserInfo: wire.TLVUserInfo{
 			TLVUserInfo: wire.TLVUserInfo{
-				ScreenName:   sess.ScreenName(),
+				ScreenName:   sess.IdentScreenName().String(),
 				WarningLevel: recipSess.Warning(),
 				WarningLevel: recipSess.Warning(),
 			},
 			},
 		}
 		}
@@ -246,7 +248,7 @@ func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFra
 		}
 		}
 	}
 	}
 
 
-	s.messageRelayer.RelayToScreenName(ctx, recipSess.ScreenName(), wire.SNACMessage{
+	s.messageRelayer.RelayToScreenName(ctx, recipSess.IdentScreenName(), wire.SNACMessage{
 		Frame: wire.SNACFrame{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.OService,
 			FoodGroup: wire.OService,
 			SubGroup:  wire.OServiceEvilNotification,
 			SubGroup:  wire.OServiceEvilNotification,

+ 22 - 29
foodgroup/icbm_test.go

@@ -229,18 +229,18 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			//
 			//
 			feedbagManager := newMockFeedbagManager(t)
 			feedbagManager := newMockFeedbagManager(t)
 			feedbagManager.EXPECT().
 			feedbagManager.EXPECT().
-				BlockedState(tc.senderSession.ScreenName(),
-					tc.inputSNAC.Body.(wire.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName).
+				BlockedState(tc.senderSession.IdentScreenName(),
+					state.NewIdentScreenName(tc.inputSNAC.Body.(wire.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName)).
 				Return(tc.blockedState, nil).
 				Return(tc.blockedState, nil).
 				Maybe()
 				Maybe()
 			messageRelayer := newMockMessageRelayer(t)
 			messageRelayer := newMockMessageRelayer(t)
 			messageRelayer.EXPECT().
 			messageRelayer.EXPECT().
-				RetrieveByScreenName(tc.inputSNAC.Body.(wire.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName).
+				RetrieveByScreenName(state.NewIdentScreenName(tc.inputSNAC.Body.(wire.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName)).
 				Return(tc.recipientSession).
 				Return(tc.recipientSession).
 				Maybe()
 				Maybe()
 			if tc.recipientSession != nil {
 			if tc.recipientSession != nil {
 				messageRelayer.EXPECT().
 				messageRelayer.EXPECT().
-					RelayToScreenName(mock.Anything, tc.recipientSession.ScreenName(), tc.expectSNACToClient).
+					RelayToScreenName(mock.Anything, tc.recipientSession.IdentScreenName(), tc.expectSNACToClient).
 					Maybe()
 					Maybe()
 			}
 			}
 			//
 			//
@@ -265,7 +265,7 @@ func TestICBMService_ClientEvent(t *testing.T) {
 		// blockedState is the response to the sender/recipient block check
 		// blockedState is the response to the sender/recipient block check
 		blockedState state.BlockedState
 		blockedState state.BlockedState
 		// senderScreenName is the screen name of the user sending the event
 		// senderScreenName is the screen name of the user sending the event
-		senderScreenName string
+		senderScreenName state.DisplayScreenName
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
 		inputSNAC wire.SNACMessage
 		inputSNAC wire.SNACMessage
 		// expectSNACToClient is the SNAC sent from the server to the
 		// expectSNACToClient is the SNAC sent from the server to the
@@ -323,13 +323,15 @@ func TestICBMService_ClientEvent(t *testing.T) {
 			//
 			//
 			feedbagManager := newMockFeedbagManager(t)
 			feedbagManager := newMockFeedbagManager(t)
 			feedbagManager.EXPECT().
 			feedbagManager.EXPECT().
-				BlockedState(tc.senderScreenName, tc.inputSNAC.Body.(wire.SNAC_0x04_0x14_ICBMClientEvent).ScreenName).
+				BlockedState(tc.senderScreenName.IdentScreenName(),
+					state.NewIdentScreenName(tc.inputSNAC.Body.(wire.SNAC_0x04_0x14_ICBMClientEvent).ScreenName)).
 				Return(tc.blockedState, nil).
 				Return(tc.blockedState, nil).
 				Maybe()
 				Maybe()
 			messageRelayer := newMockMessageRelayer(t)
 			messageRelayer := newMockMessageRelayer(t)
 			if tc.blockedState == state.BlockedNo {
 			if tc.blockedState == state.BlockedNo {
 				messageRelayer.EXPECT().
 				messageRelayer.EXPECT().
-					RelayToScreenName(mock.Anything, tc.inputSNAC.Body.(wire.SNAC_0x04_0x14_ICBMClientEvent).ScreenName,
+					RelayToScreenName(mock.Anything,
+						state.NewIdentScreenName(tc.inputSNAC.Body.(wire.SNAC_0x04_0x14_ICBMClientEvent).ScreenName),
 						tc.expectSNACToClient)
 						tc.expectSNACToClient)
 			}
 			}
 			//
 			//
@@ -357,10 +359,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 		// recipientSession is the session of the user receiving the EvilNotification
 		// recipientSession is the session of the user receiving the EvilNotification
 		recipientSession *state.Session
 		recipientSession *state.Session
 		// recipientScreenName is the screen name of the user receiving the EvilNotification
 		// recipientScreenName is the screen name of the user receiving the EvilNotification
-		recipientScreenName string
-		// recipientBuddies is a list of the recipient's buddies that get
-		// updated warning level
-		recipientBuddies []string
+		recipientScreenName state.IdentScreenName
 		// inputSNAC is the SNAC sent by the sender client
 		// inputSNAC is the SNAC sent by the sender client
 		inputSNAC wire.SNACMessage
 		inputSNAC wire.SNACMessage
 		// expectSNACToClient is the SNAC sent from the server to the
 		// expectSNACToClient is the SNAC sent from the server to the
@@ -377,8 +376,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			blockedState:        state.BlockedNo,
 			blockedState:        state.BlockedNo,
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    newTestSession("recipient-screen-name", sessOptCannedSignonTime),
 			recipientSession:    newTestSession("recipient-screen-name", sessOptCannedSignonTime),
-			recipientScreenName: "recipient-screen-name",
-			recipientBuddies:    []string{"buddy1", "buddy2"},
+			recipientScreenName: state.NewIdentScreenName("recipient-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -412,7 +410,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "recipient-screen-name",
+							screenName: state.NewIdentScreenName("recipient-screen-name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -423,8 +421,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			blockedState:        state.BlockedNo,
 			blockedState:        state.BlockedNo,
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    newTestSession("recipient-screen-name", sessOptCannedSignonTime),
 			recipientSession:    newTestSession("recipient-screen-name", sessOptCannedSignonTime),
-			recipientScreenName: "recipient-screen-name",
-			recipientBuddies:    []string{"buddy1", "buddy2"},
+			recipientScreenName: state.NewIdentScreenName("recipient-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -462,7 +459,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "recipient-screen-name",
+							screenName: state.NewIdentScreenName("recipient-screen-name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -473,8 +470,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			blockedState:        state.BlockedA,
 			blockedState:        state.BlockedA,
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    nil,
 			recipientSession:    nil,
-			recipientScreenName: "recipient-screen-name",
-			recipientBuddies:    []string{"buddy1", "buddy2"},
+			recipientScreenName: state.NewIdentScreenName("recipient-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -500,8 +496,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			blockedState:        state.BlockedB,
 			blockedState:        state.BlockedB,
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    nil,
 			recipientSession:    nil,
-			recipientScreenName: "recipient-screen-name",
-			recipientBuddies:    []string{"buddy1", "buddy2"},
+			recipientScreenName: state.NewIdentScreenName("recipient-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -526,7 +521,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			name:                "don't let users warn themselves",
 			name:                "don't let users warn themselves",
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    nil,
 			recipientSession:    nil,
-			recipientScreenName: "sender-screen-name",
+			recipientScreenName: state.NewIdentScreenName("sender-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -552,8 +547,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			blockedState:        state.BlockedNo,
 			blockedState:        state.BlockedNo,
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    nil,
 			recipientSession:    nil,
-			recipientScreenName: "recipient-screen-name",
-			recipientBuddies:    []string{"buddy1", "buddy2"},
+			recipientScreenName: state.NewIdentScreenName("recipient-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -579,8 +573,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			blockedState:        state.BlockedNo,
 			blockedState:        state.BlockedNo,
 			senderSession:       newTestSession("sender-screen-name"),
 			senderSession:       newTestSession("sender-screen-name"),
 			recipientSession:    nil,
 			recipientSession:    nil,
-			recipientScreenName: "recipient-screen-name",
-			recipientBuddies:    []string{"buddy1", "buddy2"},
+			recipientScreenName: state.NewIdentScreenName("recipient-screen-name"),
 			inputSNAC: wire.SNACMessage{
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 				Frame: wire.SNACFrame{
 					RequestID: 1234,
 					RequestID: 1234,
@@ -610,7 +603,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			//
 			//
 			feedbagManager := newMockFeedbagManager(t)
 			feedbagManager := newMockFeedbagManager(t)
 			feedbagManager.EXPECT().
 			feedbagManager.EXPECT().
-				BlockedState(tc.senderSession.ScreenName(), tc.recipientScreenName).
+				BlockedState(tc.senderSession.IdentScreenName(), tc.recipientScreenName).
 				Return(tc.blockedState, nil).
 				Return(tc.blockedState, nil).
 				Maybe()
 				Maybe()
 			messageRelayer := newMockMessageRelayer(t)
 			messageRelayer := newMockMessageRelayer(t)
@@ -626,14 +619,14 @@ func TestICBMService_EvilRequest(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}
 			//
 			//
 			// send input SNAC
 			// send input SNAC
 			//
 			//
-			senderSession := newTestSession(tc.senderSession.ScreenName())
+			senderSession := newTestSession(tc.senderSession.DisplayScreenName())
 			svc := NewICBMService(messageRelayer, feedbagManager, buddyUpdateBroadcaster)
 			svc := NewICBMService(messageRelayer, feedbagManager, buddyUpdateBroadcaster)
 			outputSNAC, err := svc.EvilRequest(nil, senderSession, tc.inputSNAC.Frame,
 			outputSNAC, err := svc.EvilRequest(nil, senderSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x04_0x08_ICBMEvilRequest))
 				tc.inputSNAC.Body.(wire.SNAC_0x04_0x08_ICBMEvilRequest))

+ 6 - 4
foodgroup/locate.go

@@ -73,7 +73,7 @@ func (s LocateService) RightsQuery(_ context.Context, inFrame wire.SNACFrame) wi
 func (s LocateService) SetInfo(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x02_0x04_LocateSetInfo) error {
 func (s LocateService) SetInfo(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x02_0x04_LocateSetInfo) error {
 	// update profile
 	// update profile
 	if profile, hasProfile := inBody.String(wire.LocateTLVTagsInfoSigData); hasProfile {
 	if profile, hasProfile := inBody.String(wire.LocateTLVTagsInfoSigData); hasProfile {
-		if err := s.profileManager.SetProfile(sess.ScreenName(), profile); err != nil {
+		if err := s.profileManager.SetProfile(sess.IdentScreenName(), profile); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -111,7 +111,9 @@ func (s LocateService) SetInfo(ctx context.Context, sess *state.Session, inBody
 // profile, if requested, and/or the away message, if requested. This is a v2
 // profile, if requested, and/or the away message, if requested. This is a v2
 // of UserInfoQuery.
 // of UserInfoQuery.
 func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x05_LocateUserInfoQuery) (wire.SNACMessage, error) {
 func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x05_LocateUserInfoQuery) (wire.SNACMessage, error) {
-	blocked, err := s.feedbagManager.BlockedState(sess.ScreenName(), inBody.ScreenName)
+	identScreenName := state.NewIdentScreenName(inBody.ScreenName)
+
+	blocked, err := s.feedbagManager.BlockedState(sess.IdentScreenName(), identScreenName)
 	switch {
 	switch {
 	case err != nil:
 	case err != nil:
 		return wire.SNACMessage{}, err
 		return wire.SNACMessage{}, err
@@ -128,7 +130,7 @@ func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inF
 		}, nil
 		}, nil
 	}
 	}
 
 
-	buddySess := s.sessionManager.RetrieveByScreenName(inBody.ScreenName)
+	buddySess := s.sessionManager.RetrieveByScreenName(identScreenName)
 	if buddySess == nil {
 	if buddySess == nil {
 		return wire.SNACMessage{
 		return wire.SNACMessage{
 			Frame: wire.SNACFrame{
 			Frame: wire.SNACFrame{
@@ -145,7 +147,7 @@ func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inF
 	var list wire.TLVList
 	var list wire.TLVList
 
 
 	if inBody.RequestProfile() {
 	if inBody.RequestProfile() {
-		profile, err := s.profileManager.Profile(inBody.ScreenName)
+		profile, err := s.profileManager.Profile(identScreenName)
 		if err != nil {
 		if err != nil {
 			return wire.SNACMessage{}, err
 			return wire.SNACMessage{}, err
 		}
 		}

+ 22 - 22
foodgroup/locate_test.go

@@ -31,8 +31,8 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					blockedStateParams: blockedStateParams{
 					blockedStateParams: blockedStateParams{
 						{
 						{
-							screenName1: "user_screen_name",
-							screenName2: "requested-user",
+							screenName1: state.NewIdentScreenName("user_screen_name"),
+							screenName2: state.NewIdentScreenName("requested-user"),
 							result:      state.BlockedNo,
 							result:      state.BlockedNo,
 						},
 						},
 					},
 					},
@@ -40,7 +40,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "requested-user",
+							screenName: state.NewIdentScreenName("requested-user"),
 							sess: newTestSession("requested-user",
 							sess: newTestSession("requested-user",
 								sessOptCannedSignonTime,
 								sessOptCannedSignonTime,
 								sessOptCannedAwayMessage),
 								sessOptCannedAwayMessage),
@@ -79,8 +79,8 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					blockedStateParams: blockedStateParams{
 					blockedStateParams: blockedStateParams{
 						{
 						{
-							screenName1: "user_screen_name",
-							screenName2: "requested-user",
+							screenName1: state.NewIdentScreenName("user_screen_name"),
+							screenName2: state.NewIdentScreenName("requested-user"),
 							result:      state.BlockedNo,
 							result:      state.BlockedNo,
 						},
 						},
 					},
 					},
@@ -88,7 +88,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "requested-user",
+							screenName: state.NewIdentScreenName("requested-user"),
 							sess: newTestSession("requested-user",
 							sess: newTestSession("requested-user",
 								sessOptCannedSignonTime,
 								sessOptCannedSignonTime,
 								sessOptCannedAwayMessage),
 								sessOptCannedAwayMessage),
@@ -98,7 +98,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				profileManagerParams: profileManagerParams{
 				profileManagerParams: profileManagerParams{
 					retrieveProfileParams: retrieveProfileParams{
 					retrieveProfileParams: retrieveProfileParams{
 						{
 						{
-							screenName: "requested-user",
+							screenName: state.NewIdentScreenName("requested-user"),
 							result:     "this is my profile!",
 							result:     "this is my profile!",
 						},
 						},
 					},
 					},
@@ -141,8 +141,8 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					blockedStateParams: blockedStateParams{
 					blockedStateParams: blockedStateParams{
 						{
 						{
-							screenName1: "user_screen_name",
-							screenName2: "requested-user",
+							screenName1: state.NewIdentScreenName("user_screen_name"),
+							screenName2: state.NewIdentScreenName("requested-user"),
 							result:      state.BlockedNo,
 							result:      state.BlockedNo,
 						},
 						},
 					},
 					},
@@ -150,7 +150,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "requested-user",
+							screenName: state.NewIdentScreenName("requested-user"),
 							sess: newTestSession("requested-user",
 							sess: newTestSession("requested-user",
 								sessOptCannedSignonTime,
 								sessOptCannedSignonTime,
 								sessOptCannedAwayMessage),
 								sessOptCannedAwayMessage),
@@ -160,7 +160,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				profileManagerParams: profileManagerParams{
 				profileManagerParams: profileManagerParams{
 					retrieveProfileParams: retrieveProfileParams{
 					retrieveProfileParams: retrieveProfileParams{
 						{
 						{
-							screenName: "requested-user",
+							screenName: state.NewIdentScreenName("requested-user"),
 							result:     "this is my profile!",
 							result:     "this is my profile!",
 						},
 						},
 					},
 					},
@@ -203,8 +203,8 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					blockedStateParams: blockedStateParams{
 					blockedStateParams: blockedStateParams{
 						{
 						{
-							screenName1: "user_screen_name",
-							screenName2: "requested-user",
+							screenName1: state.NewIdentScreenName("user_screen_name"),
+							screenName2: state.NewIdentScreenName("requested-user"),
 							result:      state.BlockedNo,
 							result:      state.BlockedNo,
 						},
 						},
 					},
 					},
@@ -212,7 +212,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "requested-user",
+							screenName: state.NewIdentScreenName("requested-user"),
 							sess: newTestSession("requested-user",
 							sess: newTestSession("requested-user",
 								sessOptCannedSignonTime,
 								sessOptCannedSignonTime,
 								sessOptCannedAwayMessage),
 								sessOptCannedAwayMessage),
@@ -257,8 +257,8 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					blockedStateParams: blockedStateParams{
 					blockedStateParams: blockedStateParams{
 						{
 						{
-							screenName1: "user_screen_name",
-							screenName2: "requested-user",
+							screenName1: state.NewIdentScreenName("user_screen_name"),
+							screenName2: state.NewIdentScreenName("requested-user"),
 							result:      state.BlockedB,
 							result:      state.BlockedB,
 						},
 						},
 					},
 					},
@@ -290,8 +290,8 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				feedbagManagerParams: feedbagManagerParams{
 				feedbagManagerParams: feedbagManagerParams{
 					blockedStateParams: blockedStateParams{
 					blockedStateParams: blockedStateParams{
 						{
 						{
-							screenName1: "user_screen_name",
-							screenName2: "non_existent_requested_user",
+							screenName1: state.NewIdentScreenName("user_screen_name"),
+							screenName2: state.NewIdentScreenName("non_existent_requested_user"),
 							result:      state.BlockedNo,
 							result:      state.BlockedNo,
 						},
 						},
 					},
 					},
@@ -299,7 +299,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "non_existent_requested_user",
+							screenName: state.NewIdentScreenName("non_existent_requested_user"),
 							sess:       nil,
 							sess:       nil,
 						},
 						},
 					},
 					},
@@ -425,7 +425,7 @@ func TestLocateService_SetInfo(t *testing.T) {
 				profileManagerParams: profileManagerParams{
 				profileManagerParams: profileManagerParams{
 					setProfileParams: setProfileParams{
 					setProfileParams: setProfileParams{
 						{
 						{
-							screenName: "test-user",
+							screenName: state.NewIdentScreenName("test-user"),
 							body:       "profile-result",
 							body:       "profile-result",
 						},
 						},
 					},
 					},
@@ -446,7 +446,7 @@ func TestLocateService_SetInfo(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -466,7 +466,7 @@ func TestLocateService_SetInfo(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}

+ 16 - 16
foodgroup/mock_chat_message_relayer_test.go

@@ -107,7 +107,7 @@ func (_c *mockChatMessageRelayer_RelayToAllExcept_Call) RunAndReturn(run func(co
 }
 }
 
 
 // RelayToScreenName provides a mock function with given fields: ctx, screenName, msg
 // RelayToScreenName provides a mock function with given fields: ctx, screenName, msg
-func (_m *mockChatMessageRelayer) RelayToScreenName(ctx context.Context, screenName string, msg wire.SNACMessage) {
+func (_m *mockChatMessageRelayer) RelayToScreenName(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage) {
 	_m.Called(ctx, screenName, msg)
 	_m.Called(ctx, screenName, msg)
 }
 }
 
 
@@ -118,15 +118,15 @@ type mockChatMessageRelayer_RelayToScreenName_Call struct {
 
 
 // RelayToScreenName is a helper method to define mock.On call
 // RelayToScreenName is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - screenName string
+//   - screenName state.IdentScreenName
 //   - msg wire.SNACMessage
 //   - msg wire.SNACMessage
 func (_e *mockChatMessageRelayer_Expecter) RelayToScreenName(ctx interface{}, screenName interface{}, msg interface{}) *mockChatMessageRelayer_RelayToScreenName_Call {
 func (_e *mockChatMessageRelayer_Expecter) RelayToScreenName(ctx interface{}, screenName interface{}, msg interface{}) *mockChatMessageRelayer_RelayToScreenName_Call {
 	return &mockChatMessageRelayer_RelayToScreenName_Call{Call: _e.mock.On("RelayToScreenName", ctx, screenName, msg)}
 	return &mockChatMessageRelayer_RelayToScreenName_Call{Call: _e.mock.On("RelayToScreenName", ctx, screenName, msg)}
 }
 }
 
 
-func (_c *mockChatMessageRelayer_RelayToScreenName_Call) Run(run func(ctx context.Context, screenName string, msg wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenName_Call {
+func (_c *mockChatMessageRelayer_RelayToScreenName_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(string), args[2].(wire.SNACMessage))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(wire.SNACMessage))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -136,13 +136,13 @@ func (_c *mockChatMessageRelayer_RelayToScreenName_Call) Return() *mockChatMessa
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatMessageRelayer_RelayToScreenName_Call) RunAndReturn(run func(context.Context, string, wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenName_Call {
+func (_c *mockChatMessageRelayer_RelayToScreenName_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenName_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // RelayToScreenNames provides a mock function with given fields: ctx, screenNames, msg
 // RelayToScreenNames provides a mock function with given fields: ctx, screenNames, msg
-func (_m *mockChatMessageRelayer) RelayToScreenNames(ctx context.Context, screenNames []string, msg wire.SNACMessage) {
+func (_m *mockChatMessageRelayer) RelayToScreenNames(ctx context.Context, screenNames []state.IdentScreenName, msg wire.SNACMessage) {
 	_m.Called(ctx, screenNames, msg)
 	_m.Called(ctx, screenNames, msg)
 }
 }
 
 
@@ -153,15 +153,15 @@ type mockChatMessageRelayer_RelayToScreenNames_Call struct {
 
 
 // RelayToScreenNames is a helper method to define mock.On call
 // RelayToScreenNames is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - screenNames []string
+//   - screenNames []state.IdentScreenName
 //   - msg wire.SNACMessage
 //   - msg wire.SNACMessage
 func (_e *mockChatMessageRelayer_Expecter) RelayToScreenNames(ctx interface{}, screenNames interface{}, msg interface{}) *mockChatMessageRelayer_RelayToScreenNames_Call {
 func (_e *mockChatMessageRelayer_Expecter) RelayToScreenNames(ctx interface{}, screenNames interface{}, msg interface{}) *mockChatMessageRelayer_RelayToScreenNames_Call {
 	return &mockChatMessageRelayer_RelayToScreenNames_Call{Call: _e.mock.On("RelayToScreenNames", ctx, screenNames, msg)}
 	return &mockChatMessageRelayer_RelayToScreenNames_Call{Call: _e.mock.On("RelayToScreenNames", ctx, screenNames, msg)}
 }
 }
 
 
-func (_c *mockChatMessageRelayer_RelayToScreenNames_Call) Run(run func(ctx context.Context, screenNames []string, msg wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenNames_Call {
+func (_c *mockChatMessageRelayer_RelayToScreenNames_Call) Run(run func(ctx context.Context, screenNames []state.IdentScreenName, msg wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenNames_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].([]string), args[2].(wire.SNACMessage))
+		run(args[0].(context.Context), args[1].([]state.IdentScreenName), args[2].(wire.SNACMessage))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -171,13 +171,13 @@ func (_c *mockChatMessageRelayer_RelayToScreenNames_Call) Return() *mockChatMess
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatMessageRelayer_RelayToScreenNames_Call) RunAndReturn(run func(context.Context, []string, wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenNames_Call {
+func (_c *mockChatMessageRelayer_RelayToScreenNames_Call) RunAndReturn(run func(context.Context, []state.IdentScreenName, wire.SNACMessage)) *mockChatMessageRelayer_RelayToScreenNames_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // RetrieveByScreenName provides a mock function with given fields: screenName
 // RetrieveByScreenName provides a mock function with given fields: screenName
-func (_m *mockChatMessageRelayer) RetrieveByScreenName(screenName string) *state.Session {
+func (_m *mockChatMessageRelayer) RetrieveByScreenName(screenName state.IdentScreenName) *state.Session {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -185,7 +185,7 @@ func (_m *mockChatMessageRelayer) RetrieveByScreenName(screenName string) *state
 	}
 	}
 
 
 	var r0 *state.Session
 	var r0 *state.Session
-	if rf, ok := ret.Get(0).(func(string) *state.Session); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.Session); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
@@ -202,14 +202,14 @@ type mockChatMessageRelayer_RetrieveByScreenName_Call struct {
 }
 }
 
 
 // RetrieveByScreenName is a helper method to define mock.On call
 // RetrieveByScreenName is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockChatMessageRelayer_Expecter) RetrieveByScreenName(screenName interface{}) *mockChatMessageRelayer_RetrieveByScreenName_Call {
 func (_e *mockChatMessageRelayer_Expecter) RetrieveByScreenName(screenName interface{}) *mockChatMessageRelayer_RetrieveByScreenName_Call {
 	return &mockChatMessageRelayer_RetrieveByScreenName_Call{Call: _e.mock.On("RetrieveByScreenName", screenName)}
 	return &mockChatMessageRelayer_RetrieveByScreenName_Call{Call: _e.mock.On("RetrieveByScreenName", screenName)}
 }
 }
 
 
-func (_c *mockChatMessageRelayer_RetrieveByScreenName_Call) Run(run func(screenName string)) *mockChatMessageRelayer_RetrieveByScreenName_Call {
+func (_c *mockChatMessageRelayer_RetrieveByScreenName_Call) Run(run func(screenName state.IdentScreenName)) *mockChatMessageRelayer_RetrieveByScreenName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -219,7 +219,7 @@ func (_c *mockChatMessageRelayer_RetrieveByScreenName_Call) Return(_a0 *state.Se
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockChatMessageRelayer_RetrieveByScreenName_Call) RunAndReturn(run func(string) *state.Session) *mockChatMessageRelayer_RetrieveByScreenName_Call {
+func (_c *mockChatMessageRelayer_RetrieveByScreenName_Call) RunAndReturn(run func(state.IdentScreenName) *state.Session) *mockChatMessageRelayer_RetrieveByScreenName_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 59 - 59
foodgroup/mock_feedbag_manager_test.go

@@ -25,27 +25,27 @@ func (_m *mockFeedbagManager) EXPECT() *mockFeedbagManager_Expecter {
 }
 }
 
 
 // AdjacentUsers provides a mock function with given fields: screenName
 // AdjacentUsers provides a mock function with given fields: screenName
-func (_m *mockFeedbagManager) AdjacentUsers(screenName string) ([]string, error) {
+func (_m *mockFeedbagManager) AdjacentUsers(screenName state.IdentScreenName) ([]state.IdentScreenName, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for AdjacentUsers")
 		panic("no return value specified for AdjacentUsers")
 	}
 	}
 
 
-	var r0 []string
+	var r0 []state.IdentScreenName
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) ([]state.IdentScreenName, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) []string); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []state.IdentScreenName); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]string)
+			r0 = ret.Get(0).([]state.IdentScreenName)
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -60,30 +60,30 @@ type mockFeedbagManager_AdjacentUsers_Call struct {
 }
 }
 
 
 // AdjacentUsers is a helper method to define mock.On call
 // AdjacentUsers is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockFeedbagManager_Expecter) AdjacentUsers(screenName interface{}) *mockFeedbagManager_AdjacentUsers_Call {
 func (_e *mockFeedbagManager_Expecter) AdjacentUsers(screenName interface{}) *mockFeedbagManager_AdjacentUsers_Call {
 	return &mockFeedbagManager_AdjacentUsers_Call{Call: _e.mock.On("AdjacentUsers", screenName)}
 	return &mockFeedbagManager_AdjacentUsers_Call{Call: _e.mock.On("AdjacentUsers", screenName)}
 }
 }
 
 
-func (_c *mockFeedbagManager_AdjacentUsers_Call) Run(run func(screenName string)) *mockFeedbagManager_AdjacentUsers_Call {
+func (_c *mockFeedbagManager_AdjacentUsers_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedbagManager_AdjacentUsers_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_AdjacentUsers_Call) Return(_a0 []string, _a1 error) *mockFeedbagManager_AdjacentUsers_Call {
+func (_c *mockFeedbagManager_AdjacentUsers_Call) Return(_a0 []state.IdentScreenName, _a1 error) *mockFeedbagManager_AdjacentUsers_Call {
 	_c.Call.Return(_a0, _a1)
 	_c.Call.Return(_a0, _a1)
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_AdjacentUsers_Call) RunAndReturn(run func(string) ([]string, error)) *mockFeedbagManager_AdjacentUsers_Call {
+func (_c *mockFeedbagManager_AdjacentUsers_Call) RunAndReturn(run func(state.IdentScreenName) ([]state.IdentScreenName, error)) *mockFeedbagManager_AdjacentUsers_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // BlockedState provides a mock function with given fields: screenName1, screenName2
 // BlockedState provides a mock function with given fields: screenName1, screenName2
-func (_m *mockFeedbagManager) BlockedState(screenName1 string, screenName2 string) (state.BlockedState, error) {
+func (_m *mockFeedbagManager) BlockedState(screenName1 state.IdentScreenName, screenName2 state.IdentScreenName) (state.BlockedState, error) {
 	ret := _m.Called(screenName1, screenName2)
 	ret := _m.Called(screenName1, screenName2)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -92,16 +92,16 @@ func (_m *mockFeedbagManager) BlockedState(screenName1 string, screenName2 strin
 
 
 	var r0 state.BlockedState
 	var r0 state.BlockedState
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string, string) (state.BlockedState, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) (state.BlockedState, error)); ok {
 		return rf(screenName1, screenName2)
 		return rf(screenName1, screenName2)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string, string) state.BlockedState); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) state.BlockedState); ok {
 		r0 = rf(screenName1, screenName2)
 		r0 = rf(screenName1, screenName2)
 	} else {
 	} else {
 		r0 = ret.Get(0).(state.BlockedState)
 		r0 = ret.Get(0).(state.BlockedState)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string, string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
 		r1 = rf(screenName1, screenName2)
 		r1 = rf(screenName1, screenName2)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -116,15 +116,15 @@ type mockFeedbagManager_BlockedState_Call struct {
 }
 }
 
 
 // BlockedState is a helper method to define mock.On call
 // BlockedState is a helper method to define mock.On call
-//   - screenName1 string
-//   - screenName2 string
+//   - screenName1 state.IdentScreenName
+//   - screenName2 state.IdentScreenName
 func (_e *mockFeedbagManager_Expecter) BlockedState(screenName1 interface{}, screenName2 interface{}) *mockFeedbagManager_BlockedState_Call {
 func (_e *mockFeedbagManager_Expecter) BlockedState(screenName1 interface{}, screenName2 interface{}) *mockFeedbagManager_BlockedState_Call {
 	return &mockFeedbagManager_BlockedState_Call{Call: _e.mock.On("BlockedState", screenName1, screenName2)}
 	return &mockFeedbagManager_BlockedState_Call{Call: _e.mock.On("BlockedState", screenName1, screenName2)}
 }
 }
 
 
-func (_c *mockFeedbagManager_BlockedState_Call) Run(run func(screenName1 string, screenName2 string)) *mockFeedbagManager_BlockedState_Call {
+func (_c *mockFeedbagManager_BlockedState_Call) Run(run func(screenName1 state.IdentScreenName, screenName2 state.IdentScreenName)) *mockFeedbagManager_BlockedState_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].(string))
+		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -134,33 +134,33 @@ func (_c *mockFeedbagManager_BlockedState_Call) Return(_a0 state.BlockedState, _
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_BlockedState_Call) RunAndReturn(run func(string, string) (state.BlockedState, error)) *mockFeedbagManager_BlockedState_Call {
+func (_c *mockFeedbagManager_BlockedState_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) (state.BlockedState, error)) *mockFeedbagManager_BlockedState_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // Buddies provides a mock function with given fields: screenName
 // Buddies provides a mock function with given fields: screenName
-func (_m *mockFeedbagManager) Buddies(screenName string) ([]string, error) {
+func (_m *mockFeedbagManager) Buddies(screenName state.IdentScreenName) ([]state.IdentScreenName, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for Buddies")
 		panic("no return value specified for Buddies")
 	}
 	}
 
 
-	var r0 []string
+	var r0 []state.IdentScreenName
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) ([]state.IdentScreenName, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) []string); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []state.IdentScreenName); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]string)
+			r0 = ret.Get(0).([]state.IdentScreenName)
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -175,30 +175,30 @@ type mockFeedbagManager_Buddies_Call struct {
 }
 }
 
 
 // Buddies is a helper method to define mock.On call
 // Buddies is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockFeedbagManager_Expecter) Buddies(screenName interface{}) *mockFeedbagManager_Buddies_Call {
 func (_e *mockFeedbagManager_Expecter) Buddies(screenName interface{}) *mockFeedbagManager_Buddies_Call {
 	return &mockFeedbagManager_Buddies_Call{Call: _e.mock.On("Buddies", screenName)}
 	return &mockFeedbagManager_Buddies_Call{Call: _e.mock.On("Buddies", screenName)}
 }
 }
 
 
-func (_c *mockFeedbagManager_Buddies_Call) Run(run func(screenName string)) *mockFeedbagManager_Buddies_Call {
+func (_c *mockFeedbagManager_Buddies_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedbagManager_Buddies_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_Buddies_Call) Return(_a0 []string, _a1 error) *mockFeedbagManager_Buddies_Call {
+func (_c *mockFeedbagManager_Buddies_Call) Return(_a0 []state.IdentScreenName, _a1 error) *mockFeedbagManager_Buddies_Call {
 	_c.Call.Return(_a0, _a1)
 	_c.Call.Return(_a0, _a1)
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_Buddies_Call) RunAndReturn(run func(string) ([]string, error)) *mockFeedbagManager_Buddies_Call {
+func (_c *mockFeedbagManager_Buddies_Call) RunAndReturn(run func(state.IdentScreenName) ([]state.IdentScreenName, error)) *mockFeedbagManager_Buddies_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // Feedbag provides a mock function with given fields: screenName
 // Feedbag provides a mock function with given fields: screenName
-func (_m *mockFeedbagManager) Feedbag(screenName string) ([]wire.FeedbagItem, error) {
+func (_m *mockFeedbagManager) Feedbag(screenName state.IdentScreenName) ([]wire.FeedbagItem, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -207,10 +207,10 @@ func (_m *mockFeedbagManager) Feedbag(screenName string) ([]wire.FeedbagItem, er
 
 
 	var r0 []wire.FeedbagItem
 	var r0 []wire.FeedbagItem
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) ([]wire.FeedbagItem, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) ([]wire.FeedbagItem, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) []wire.FeedbagItem); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []wire.FeedbagItem); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
@@ -218,7 +218,7 @@ func (_m *mockFeedbagManager) Feedbag(screenName string) ([]wire.FeedbagItem, er
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -233,14 +233,14 @@ type mockFeedbagManager_Feedbag_Call struct {
 }
 }
 
 
 // Feedbag is a helper method to define mock.On call
 // Feedbag is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockFeedbagManager_Expecter) Feedbag(screenName interface{}) *mockFeedbagManager_Feedbag_Call {
 func (_e *mockFeedbagManager_Expecter) Feedbag(screenName interface{}) *mockFeedbagManager_Feedbag_Call {
 	return &mockFeedbagManager_Feedbag_Call{Call: _e.mock.On("Feedbag", screenName)}
 	return &mockFeedbagManager_Feedbag_Call{Call: _e.mock.On("Feedbag", screenName)}
 }
 }
 
 
-func (_c *mockFeedbagManager_Feedbag_Call) Run(run func(screenName string)) *mockFeedbagManager_Feedbag_Call {
+func (_c *mockFeedbagManager_Feedbag_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedbagManager_Feedbag_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -250,13 +250,13 @@ func (_c *mockFeedbagManager_Feedbag_Call) Return(_a0 []wire.FeedbagItem, _a1 er
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_Feedbag_Call) RunAndReturn(run func(string) ([]wire.FeedbagItem, error)) *mockFeedbagManager_Feedbag_Call {
+func (_c *mockFeedbagManager_Feedbag_Call) RunAndReturn(run func(state.IdentScreenName) ([]wire.FeedbagItem, error)) *mockFeedbagManager_Feedbag_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // FeedbagDelete provides a mock function with given fields: screenName, items
 // FeedbagDelete provides a mock function with given fields: screenName, items
-func (_m *mockFeedbagManager) FeedbagDelete(screenName string, items []wire.FeedbagItem) error {
+func (_m *mockFeedbagManager) FeedbagDelete(screenName state.IdentScreenName, items []wire.FeedbagItem) error {
 	ret := _m.Called(screenName, items)
 	ret := _m.Called(screenName, items)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -264,7 +264,7 @@ func (_m *mockFeedbagManager) FeedbagDelete(screenName string, items []wire.Feed
 	}
 	}
 
 
 	var r0 error
 	var r0 error
-	if rf, ok := ret.Get(0).(func(string, []wire.FeedbagItem) error); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName, []wire.FeedbagItem) error); ok {
 		r0 = rf(screenName, items)
 		r0 = rf(screenName, items)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
@@ -279,15 +279,15 @@ type mockFeedbagManager_FeedbagDelete_Call struct {
 }
 }
 
 
 // FeedbagDelete is a helper method to define mock.On call
 // FeedbagDelete is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 //   - items []wire.FeedbagItem
 //   - items []wire.FeedbagItem
 func (_e *mockFeedbagManager_Expecter) FeedbagDelete(screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagDelete_Call {
 func (_e *mockFeedbagManager_Expecter) FeedbagDelete(screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagDelete_Call {
 	return &mockFeedbagManager_FeedbagDelete_Call{Call: _e.mock.On("FeedbagDelete", screenName, items)}
 	return &mockFeedbagManager_FeedbagDelete_Call{Call: _e.mock.On("FeedbagDelete", screenName, items)}
 }
 }
 
 
-func (_c *mockFeedbagManager_FeedbagDelete_Call) Run(run func(screenName string, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagDelete_Call {
+func (_c *mockFeedbagManager_FeedbagDelete_Call) Run(run func(screenName state.IdentScreenName, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagDelete_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].([]wire.FeedbagItem))
+		run(args[0].(state.IdentScreenName), args[1].([]wire.FeedbagItem))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -297,13 +297,13 @@ func (_c *mockFeedbagManager_FeedbagDelete_Call) Return(_a0 error) *mockFeedbagM
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_FeedbagDelete_Call) RunAndReturn(run func(string, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagDelete_Call {
+func (_c *mockFeedbagManager_FeedbagDelete_Call) RunAndReturn(run func(state.IdentScreenName, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagDelete_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // FeedbagLastModified provides a mock function with given fields: screenName
 // FeedbagLastModified provides a mock function with given fields: screenName
-func (_m *mockFeedbagManager) FeedbagLastModified(screenName string) (time.Time, error) {
+func (_m *mockFeedbagManager) FeedbagLastModified(screenName state.IdentScreenName) (time.Time, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -312,16 +312,16 @@ func (_m *mockFeedbagManager) FeedbagLastModified(screenName string) (time.Time,
 
 
 	var r0 time.Time
 	var r0 time.Time
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (time.Time, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (time.Time, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) time.Time); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) time.Time); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		r0 = ret.Get(0).(time.Time)
 		r0 = ret.Get(0).(time.Time)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -336,14 +336,14 @@ type mockFeedbagManager_FeedbagLastModified_Call struct {
 }
 }
 
 
 // FeedbagLastModified is a helper method to define mock.On call
 // FeedbagLastModified is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockFeedbagManager_Expecter) FeedbagLastModified(screenName interface{}) *mockFeedbagManager_FeedbagLastModified_Call {
 func (_e *mockFeedbagManager_Expecter) FeedbagLastModified(screenName interface{}) *mockFeedbagManager_FeedbagLastModified_Call {
 	return &mockFeedbagManager_FeedbagLastModified_Call{Call: _e.mock.On("FeedbagLastModified", screenName)}
 	return &mockFeedbagManager_FeedbagLastModified_Call{Call: _e.mock.On("FeedbagLastModified", screenName)}
 }
 }
 
 
-func (_c *mockFeedbagManager_FeedbagLastModified_Call) Run(run func(screenName string)) *mockFeedbagManager_FeedbagLastModified_Call {
+func (_c *mockFeedbagManager_FeedbagLastModified_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedbagManager_FeedbagLastModified_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -353,13 +353,13 @@ func (_c *mockFeedbagManager_FeedbagLastModified_Call) Return(_a0 time.Time, _a1
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_FeedbagLastModified_Call) RunAndReturn(run func(string) (time.Time, error)) *mockFeedbagManager_FeedbagLastModified_Call {
+func (_c *mockFeedbagManager_FeedbagLastModified_Call) RunAndReturn(run func(state.IdentScreenName) (time.Time, error)) *mockFeedbagManager_FeedbagLastModified_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // FeedbagUpsert provides a mock function with given fields: screenName, items
 // FeedbagUpsert provides a mock function with given fields: screenName, items
-func (_m *mockFeedbagManager) FeedbagUpsert(screenName string, items []wire.FeedbagItem) error {
+func (_m *mockFeedbagManager) FeedbagUpsert(screenName state.IdentScreenName, items []wire.FeedbagItem) error {
 	ret := _m.Called(screenName, items)
 	ret := _m.Called(screenName, items)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -367,7 +367,7 @@ func (_m *mockFeedbagManager) FeedbagUpsert(screenName string, items []wire.Feed
 	}
 	}
 
 
 	var r0 error
 	var r0 error
-	if rf, ok := ret.Get(0).(func(string, []wire.FeedbagItem) error); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName, []wire.FeedbagItem) error); ok {
 		r0 = rf(screenName, items)
 		r0 = rf(screenName, items)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
@@ -382,15 +382,15 @@ type mockFeedbagManager_FeedbagUpsert_Call struct {
 }
 }
 
 
 // FeedbagUpsert is a helper method to define mock.On call
 // FeedbagUpsert is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 //   - items []wire.FeedbagItem
 //   - items []wire.FeedbagItem
 func (_e *mockFeedbagManager_Expecter) FeedbagUpsert(screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagUpsert_Call {
 func (_e *mockFeedbagManager_Expecter) FeedbagUpsert(screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagUpsert_Call {
 	return &mockFeedbagManager_FeedbagUpsert_Call{Call: _e.mock.On("FeedbagUpsert", screenName, items)}
 	return &mockFeedbagManager_FeedbagUpsert_Call{Call: _e.mock.On("FeedbagUpsert", screenName, items)}
 }
 }
 
 
-func (_c *mockFeedbagManager_FeedbagUpsert_Call) Run(run func(screenName string, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagUpsert_Call {
+func (_c *mockFeedbagManager_FeedbagUpsert_Call) Run(run func(screenName state.IdentScreenName, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagUpsert_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].([]wire.FeedbagItem))
+		run(args[0].(state.IdentScreenName), args[1].([]wire.FeedbagItem))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -400,7 +400,7 @@ func (_c *mockFeedbagManager_FeedbagUpsert_Call) Return(_a0 error) *mockFeedbagM
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockFeedbagManager_FeedbagUpsert_Call) RunAndReturn(run func(string, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagUpsert_Call {
+func (_c *mockFeedbagManager_FeedbagUpsert_Call) RunAndReturn(run func(state.IdentScreenName, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagUpsert_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 39 - 36
foodgroup/mock_legacy_buddy_list_manager_test.go

@@ -2,7 +2,10 @@
 
 
 package foodgroup
 package foodgroup
 
 
-import mock "github.com/stretchr/testify/mock"
+import (
+	state "github.com/mk6i/retro-aim-server/state"
+	mock "github.com/stretchr/testify/mock"
+)
 
 
 // mockLegacyBuddyListManager is an autogenerated mock type for the LegacyBuddyListManager type
 // mockLegacyBuddyListManager is an autogenerated mock type for the LegacyBuddyListManager type
 type mockLegacyBuddyListManager struct {
 type mockLegacyBuddyListManager struct {
@@ -18,7 +21,7 @@ func (_m *mockLegacyBuddyListManager) EXPECT() *mockLegacyBuddyListManager_Expec
 }
 }
 
 
 // AddBuddy provides a mock function with given fields: userScreenName, buddyScreenName
 // AddBuddy provides a mock function with given fields: userScreenName, buddyScreenName
-func (_m *mockLegacyBuddyListManager) AddBuddy(userScreenName string, buddyScreenName string) {
+func (_m *mockLegacyBuddyListManager) AddBuddy(userScreenName state.IdentScreenName, buddyScreenName state.IdentScreenName) {
 	_m.Called(userScreenName, buddyScreenName)
 	_m.Called(userScreenName, buddyScreenName)
 }
 }
 
 
@@ -28,15 +31,15 @@ type mockLegacyBuddyListManager_AddBuddy_Call struct {
 }
 }
 
 
 // AddBuddy is a helper method to define mock.On call
 // AddBuddy is a helper method to define mock.On call
-//   - userScreenName string
-//   - buddyScreenName string
+//   - userScreenName state.IdentScreenName
+//   - buddyScreenName state.IdentScreenName
 func (_e *mockLegacyBuddyListManager_Expecter) AddBuddy(userScreenName interface{}, buddyScreenName interface{}) *mockLegacyBuddyListManager_AddBuddy_Call {
 func (_e *mockLegacyBuddyListManager_Expecter) AddBuddy(userScreenName interface{}, buddyScreenName interface{}) *mockLegacyBuddyListManager_AddBuddy_Call {
 	return &mockLegacyBuddyListManager_AddBuddy_Call{Call: _e.mock.On("AddBuddy", userScreenName, buddyScreenName)}
 	return &mockLegacyBuddyListManager_AddBuddy_Call{Call: _e.mock.On("AddBuddy", userScreenName, buddyScreenName)}
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_AddBuddy_Call) Run(run func(userScreenName string, buddyScreenName string)) *mockLegacyBuddyListManager_AddBuddy_Call {
+func (_c *mockLegacyBuddyListManager_AddBuddy_Call) Run(run func(userScreenName state.IdentScreenName, buddyScreenName state.IdentScreenName)) *mockLegacyBuddyListManager_AddBuddy_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].(string))
+		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -46,25 +49,25 @@ func (_c *mockLegacyBuddyListManager_AddBuddy_Call) Return() *mockLegacyBuddyLis
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_AddBuddy_Call) RunAndReturn(run func(string, string)) *mockLegacyBuddyListManager_AddBuddy_Call {
+func (_c *mockLegacyBuddyListManager_AddBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName)) *mockLegacyBuddyListManager_AddBuddy_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // Buddies provides a mock function with given fields: userScreenName
 // Buddies provides a mock function with given fields: userScreenName
-func (_m *mockLegacyBuddyListManager) Buddies(userScreenName string) []string {
+func (_m *mockLegacyBuddyListManager) Buddies(userScreenName state.IdentScreenName) []state.IdentScreenName {
 	ret := _m.Called(userScreenName)
 	ret := _m.Called(userScreenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for Buddies")
 		panic("no return value specified for Buddies")
 	}
 	}
 
 
-	var r0 []string
-	if rf, ok := ret.Get(0).(func(string) []string); ok {
+	var r0 []state.IdentScreenName
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []state.IdentScreenName); ok {
 		r0 = rf(userScreenName)
 		r0 = rf(userScreenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]string)
+			r0 = ret.Get(0).([]state.IdentScreenName)
 		}
 		}
 	}
 	}
 
 
@@ -77,30 +80,30 @@ type mockLegacyBuddyListManager_Buddies_Call struct {
 }
 }
 
 
 // Buddies is a helper method to define mock.On call
 // Buddies is a helper method to define mock.On call
-//   - userScreenName string
+//   - userScreenName state.IdentScreenName
 func (_e *mockLegacyBuddyListManager_Expecter) Buddies(userScreenName interface{}) *mockLegacyBuddyListManager_Buddies_Call {
 func (_e *mockLegacyBuddyListManager_Expecter) Buddies(userScreenName interface{}) *mockLegacyBuddyListManager_Buddies_Call {
 	return &mockLegacyBuddyListManager_Buddies_Call{Call: _e.mock.On("Buddies", userScreenName)}
 	return &mockLegacyBuddyListManager_Buddies_Call{Call: _e.mock.On("Buddies", userScreenName)}
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_Buddies_Call) Run(run func(userScreenName string)) *mockLegacyBuddyListManager_Buddies_Call {
+func (_c *mockLegacyBuddyListManager_Buddies_Call) Run(run func(userScreenName state.IdentScreenName)) *mockLegacyBuddyListManager_Buddies_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_Buddies_Call) Return(_a0 []string) *mockLegacyBuddyListManager_Buddies_Call {
+func (_c *mockLegacyBuddyListManager_Buddies_Call) Return(_a0 []state.IdentScreenName) *mockLegacyBuddyListManager_Buddies_Call {
 	_c.Call.Return(_a0)
 	_c.Call.Return(_a0)
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_Buddies_Call) RunAndReturn(run func(string) []string) *mockLegacyBuddyListManager_Buddies_Call {
+func (_c *mockLegacyBuddyListManager_Buddies_Call) RunAndReturn(run func(state.IdentScreenName) []state.IdentScreenName) *mockLegacyBuddyListManager_Buddies_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // DeleteBuddy provides a mock function with given fields: userScreenName, buddyScreenName
 // DeleteBuddy provides a mock function with given fields: userScreenName, buddyScreenName
-func (_m *mockLegacyBuddyListManager) DeleteBuddy(userScreenName string, buddyScreenName string) {
+func (_m *mockLegacyBuddyListManager) DeleteBuddy(userScreenName state.IdentScreenName, buddyScreenName state.IdentScreenName) {
 	_m.Called(userScreenName, buddyScreenName)
 	_m.Called(userScreenName, buddyScreenName)
 }
 }
 
 
@@ -110,15 +113,15 @@ type mockLegacyBuddyListManager_DeleteBuddy_Call struct {
 }
 }
 
 
 // DeleteBuddy is a helper method to define mock.On call
 // DeleteBuddy is a helper method to define mock.On call
-//   - userScreenName string
-//   - buddyScreenName string
+//   - userScreenName state.IdentScreenName
+//   - buddyScreenName state.IdentScreenName
 func (_e *mockLegacyBuddyListManager_Expecter) DeleteBuddy(userScreenName interface{}, buddyScreenName interface{}) *mockLegacyBuddyListManager_DeleteBuddy_Call {
 func (_e *mockLegacyBuddyListManager_Expecter) DeleteBuddy(userScreenName interface{}, buddyScreenName interface{}) *mockLegacyBuddyListManager_DeleteBuddy_Call {
 	return &mockLegacyBuddyListManager_DeleteBuddy_Call{Call: _e.mock.On("DeleteBuddy", userScreenName, buddyScreenName)}
 	return &mockLegacyBuddyListManager_DeleteBuddy_Call{Call: _e.mock.On("DeleteBuddy", userScreenName, buddyScreenName)}
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_DeleteBuddy_Call) Run(run func(userScreenName string, buddyScreenName string)) *mockLegacyBuddyListManager_DeleteBuddy_Call {
+func (_c *mockLegacyBuddyListManager_DeleteBuddy_Call) Run(run func(userScreenName state.IdentScreenName, buddyScreenName state.IdentScreenName)) *mockLegacyBuddyListManager_DeleteBuddy_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].(string))
+		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -128,13 +131,13 @@ func (_c *mockLegacyBuddyListManager_DeleteBuddy_Call) Return() *mockLegacyBuddy
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_DeleteBuddy_Call) RunAndReturn(run func(string, string)) *mockLegacyBuddyListManager_DeleteBuddy_Call {
+func (_c *mockLegacyBuddyListManager_DeleteBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName)) *mockLegacyBuddyListManager_DeleteBuddy_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // DeleteUser provides a mock function with given fields: userScreenName
 // DeleteUser provides a mock function with given fields: userScreenName
-func (_m *mockLegacyBuddyListManager) DeleteUser(userScreenName string) {
+func (_m *mockLegacyBuddyListManager) DeleteUser(userScreenName state.IdentScreenName) {
 	_m.Called(userScreenName)
 	_m.Called(userScreenName)
 }
 }
 
 
@@ -144,14 +147,14 @@ type mockLegacyBuddyListManager_DeleteUser_Call struct {
 }
 }
 
 
 // DeleteUser is a helper method to define mock.On call
 // DeleteUser is a helper method to define mock.On call
-//   - userScreenName string
+//   - userScreenName state.IdentScreenName
 func (_e *mockLegacyBuddyListManager_Expecter) DeleteUser(userScreenName interface{}) *mockLegacyBuddyListManager_DeleteUser_Call {
 func (_e *mockLegacyBuddyListManager_Expecter) DeleteUser(userScreenName interface{}) *mockLegacyBuddyListManager_DeleteUser_Call {
 	return &mockLegacyBuddyListManager_DeleteUser_Call{Call: _e.mock.On("DeleteUser", userScreenName)}
 	return &mockLegacyBuddyListManager_DeleteUser_Call{Call: _e.mock.On("DeleteUser", userScreenName)}
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_DeleteUser_Call) Run(run func(userScreenName string)) *mockLegacyBuddyListManager_DeleteUser_Call {
+func (_c *mockLegacyBuddyListManager_DeleteUser_Call) Run(run func(userScreenName state.IdentScreenName)) *mockLegacyBuddyListManager_DeleteUser_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -161,25 +164,25 @@ func (_c *mockLegacyBuddyListManager_DeleteUser_Call) Return() *mockLegacyBuddyL
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_DeleteUser_Call) RunAndReturn(run func(string)) *mockLegacyBuddyListManager_DeleteUser_Call {
+func (_c *mockLegacyBuddyListManager_DeleteUser_Call) RunAndReturn(run func(state.IdentScreenName)) *mockLegacyBuddyListManager_DeleteUser_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // WhoAddedUser provides a mock function with given fields: userScreenName
 // WhoAddedUser provides a mock function with given fields: userScreenName
-func (_m *mockLegacyBuddyListManager) WhoAddedUser(userScreenName string) []string {
+func (_m *mockLegacyBuddyListManager) WhoAddedUser(userScreenName state.IdentScreenName) []state.IdentScreenName {
 	ret := _m.Called(userScreenName)
 	ret := _m.Called(userScreenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for WhoAddedUser")
 		panic("no return value specified for WhoAddedUser")
 	}
 	}
 
 
-	var r0 []string
-	if rf, ok := ret.Get(0).(func(string) []string); ok {
+	var r0 []state.IdentScreenName
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []state.IdentScreenName); ok {
 		r0 = rf(userScreenName)
 		r0 = rf(userScreenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]string)
+			r0 = ret.Get(0).([]state.IdentScreenName)
 		}
 		}
 	}
 	}
 
 
@@ -192,24 +195,24 @@ type mockLegacyBuddyListManager_WhoAddedUser_Call struct {
 }
 }
 
 
 // WhoAddedUser is a helper method to define mock.On call
 // WhoAddedUser is a helper method to define mock.On call
-//   - userScreenName string
+//   - userScreenName state.IdentScreenName
 func (_e *mockLegacyBuddyListManager_Expecter) WhoAddedUser(userScreenName interface{}) *mockLegacyBuddyListManager_WhoAddedUser_Call {
 func (_e *mockLegacyBuddyListManager_Expecter) WhoAddedUser(userScreenName interface{}) *mockLegacyBuddyListManager_WhoAddedUser_Call {
 	return &mockLegacyBuddyListManager_WhoAddedUser_Call{Call: _e.mock.On("WhoAddedUser", userScreenName)}
 	return &mockLegacyBuddyListManager_WhoAddedUser_Call{Call: _e.mock.On("WhoAddedUser", userScreenName)}
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_WhoAddedUser_Call) Run(run func(userScreenName string)) *mockLegacyBuddyListManager_WhoAddedUser_Call {
+func (_c *mockLegacyBuddyListManager_WhoAddedUser_Call) Run(run func(userScreenName state.IdentScreenName)) *mockLegacyBuddyListManager_WhoAddedUser_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_WhoAddedUser_Call) Return(_a0 []string) *mockLegacyBuddyListManager_WhoAddedUser_Call {
+func (_c *mockLegacyBuddyListManager_WhoAddedUser_Call) Return(_a0 []state.IdentScreenName) *mockLegacyBuddyListManager_WhoAddedUser_Call {
 	_c.Call.Return(_a0)
 	_c.Call.Return(_a0)
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockLegacyBuddyListManager_WhoAddedUser_Call) RunAndReturn(run func(string) []string) *mockLegacyBuddyListManager_WhoAddedUser_Call {
+func (_c *mockLegacyBuddyListManager_WhoAddedUser_Call) RunAndReturn(run func(state.IdentScreenName) []state.IdentScreenName) *mockLegacyBuddyListManager_WhoAddedUser_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 16 - 16
foodgroup/mock_message_relayer_test.go

@@ -25,7 +25,7 @@ func (_m *mockMessageRelayer) EXPECT() *mockMessageRelayer_Expecter {
 }
 }
 
 
 // RelayToScreenName provides a mock function with given fields: ctx, screenName, msg
 // RelayToScreenName provides a mock function with given fields: ctx, screenName, msg
-func (_m *mockMessageRelayer) RelayToScreenName(ctx context.Context, screenName string, msg wire.SNACMessage) {
+func (_m *mockMessageRelayer) RelayToScreenName(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage) {
 	_m.Called(ctx, screenName, msg)
 	_m.Called(ctx, screenName, msg)
 }
 }
 
 
@@ -36,15 +36,15 @@ type mockMessageRelayer_RelayToScreenName_Call struct {
 
 
 // RelayToScreenName is a helper method to define mock.On call
 // RelayToScreenName is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - screenName string
+//   - screenName state.IdentScreenName
 //   - msg wire.SNACMessage
 //   - msg wire.SNACMessage
 func (_e *mockMessageRelayer_Expecter) RelayToScreenName(ctx interface{}, screenName interface{}, msg interface{}) *mockMessageRelayer_RelayToScreenName_Call {
 func (_e *mockMessageRelayer_Expecter) RelayToScreenName(ctx interface{}, screenName interface{}, msg interface{}) *mockMessageRelayer_RelayToScreenName_Call {
 	return &mockMessageRelayer_RelayToScreenName_Call{Call: _e.mock.On("RelayToScreenName", ctx, screenName, msg)}
 	return &mockMessageRelayer_RelayToScreenName_Call{Call: _e.mock.On("RelayToScreenName", ctx, screenName, msg)}
 }
 }
 
 
-func (_c *mockMessageRelayer_RelayToScreenName_Call) Run(run func(ctx context.Context, screenName string, msg wire.SNACMessage)) *mockMessageRelayer_RelayToScreenName_Call {
+func (_c *mockMessageRelayer_RelayToScreenName_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage)) *mockMessageRelayer_RelayToScreenName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(string), args[2].(wire.SNACMessage))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(wire.SNACMessage))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -54,13 +54,13 @@ func (_c *mockMessageRelayer_RelayToScreenName_Call) Return() *mockMessageRelaye
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockMessageRelayer_RelayToScreenName_Call) RunAndReturn(run func(context.Context, string, wire.SNACMessage)) *mockMessageRelayer_RelayToScreenName_Call {
+func (_c *mockMessageRelayer_RelayToScreenName_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, wire.SNACMessage)) *mockMessageRelayer_RelayToScreenName_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // RelayToScreenNames provides a mock function with given fields: ctx, screenNames, msg
 // RelayToScreenNames provides a mock function with given fields: ctx, screenNames, msg
-func (_m *mockMessageRelayer) RelayToScreenNames(ctx context.Context, screenNames []string, msg wire.SNACMessage) {
+func (_m *mockMessageRelayer) RelayToScreenNames(ctx context.Context, screenNames []state.IdentScreenName, msg wire.SNACMessage) {
 	_m.Called(ctx, screenNames, msg)
 	_m.Called(ctx, screenNames, msg)
 }
 }
 
 
@@ -71,15 +71,15 @@ type mockMessageRelayer_RelayToScreenNames_Call struct {
 
 
 // RelayToScreenNames is a helper method to define mock.On call
 // RelayToScreenNames is a helper method to define mock.On call
 //   - ctx context.Context
 //   - ctx context.Context
-//   - screenNames []string
+//   - screenNames []state.IdentScreenName
 //   - msg wire.SNACMessage
 //   - msg wire.SNACMessage
 func (_e *mockMessageRelayer_Expecter) RelayToScreenNames(ctx interface{}, screenNames interface{}, msg interface{}) *mockMessageRelayer_RelayToScreenNames_Call {
 func (_e *mockMessageRelayer_Expecter) RelayToScreenNames(ctx interface{}, screenNames interface{}, msg interface{}) *mockMessageRelayer_RelayToScreenNames_Call {
 	return &mockMessageRelayer_RelayToScreenNames_Call{Call: _e.mock.On("RelayToScreenNames", ctx, screenNames, msg)}
 	return &mockMessageRelayer_RelayToScreenNames_Call{Call: _e.mock.On("RelayToScreenNames", ctx, screenNames, msg)}
 }
 }
 
 
-func (_c *mockMessageRelayer_RelayToScreenNames_Call) Run(run func(ctx context.Context, screenNames []string, msg wire.SNACMessage)) *mockMessageRelayer_RelayToScreenNames_Call {
+func (_c *mockMessageRelayer_RelayToScreenNames_Call) Run(run func(ctx context.Context, screenNames []state.IdentScreenName, msg wire.SNACMessage)) *mockMessageRelayer_RelayToScreenNames_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].([]string), args[2].(wire.SNACMessage))
+		run(args[0].(context.Context), args[1].([]state.IdentScreenName), args[2].(wire.SNACMessage))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -89,13 +89,13 @@ func (_c *mockMessageRelayer_RelayToScreenNames_Call) Return() *mockMessageRelay
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockMessageRelayer_RelayToScreenNames_Call) RunAndReturn(run func(context.Context, []string, wire.SNACMessage)) *mockMessageRelayer_RelayToScreenNames_Call {
+func (_c *mockMessageRelayer_RelayToScreenNames_Call) RunAndReturn(run func(context.Context, []state.IdentScreenName, wire.SNACMessage)) *mockMessageRelayer_RelayToScreenNames_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // RetrieveByScreenName provides a mock function with given fields: screenName
 // RetrieveByScreenName provides a mock function with given fields: screenName
-func (_m *mockMessageRelayer) RetrieveByScreenName(screenName string) *state.Session {
+func (_m *mockMessageRelayer) RetrieveByScreenName(screenName state.IdentScreenName) *state.Session {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -103,7 +103,7 @@ func (_m *mockMessageRelayer) RetrieveByScreenName(screenName string) *state.Ses
 	}
 	}
 
 
 	var r0 *state.Session
 	var r0 *state.Session
-	if rf, ok := ret.Get(0).(func(string) *state.Session); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.Session); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
@@ -120,14 +120,14 @@ type mockMessageRelayer_RetrieveByScreenName_Call struct {
 }
 }
 
 
 // RetrieveByScreenName is a helper method to define mock.On call
 // RetrieveByScreenName is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockMessageRelayer_Expecter) RetrieveByScreenName(screenName interface{}) *mockMessageRelayer_RetrieveByScreenName_Call {
 func (_e *mockMessageRelayer_Expecter) RetrieveByScreenName(screenName interface{}) *mockMessageRelayer_RetrieveByScreenName_Call {
 	return &mockMessageRelayer_RetrieveByScreenName_Call{Call: _e.mock.On("RetrieveByScreenName", screenName)}
 	return &mockMessageRelayer_RetrieveByScreenName_Call{Call: _e.mock.On("RetrieveByScreenName", screenName)}
 }
 }
 
 
-func (_c *mockMessageRelayer_RetrieveByScreenName_Call) Run(run func(screenName string)) *mockMessageRelayer_RetrieveByScreenName_Call {
+func (_c *mockMessageRelayer_RetrieveByScreenName_Call) Run(run func(screenName state.IdentScreenName)) *mockMessageRelayer_RetrieveByScreenName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -137,7 +137,7 @@ func (_c *mockMessageRelayer_RetrieveByScreenName_Call) Return(_a0 *state.Sessio
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockMessageRelayer_RetrieveByScreenName_Call) RunAndReturn(run func(string) *state.Session) *mockMessageRelayer_RetrieveByScreenName_Call {
+func (_c *mockMessageRelayer_RetrieveByScreenName_Call) RunAndReturn(run func(state.IdentScreenName) *state.Session) *mockMessageRelayer_RetrieveByScreenName_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 18 - 15
foodgroup/mock_profile_manager_test.go

@@ -2,7 +2,10 @@
 
 
 package foodgroup
 package foodgroup
 
 
-import mock "github.com/stretchr/testify/mock"
+import (
+	state "github.com/mk6i/retro-aim-server/state"
+	mock "github.com/stretchr/testify/mock"
+)
 
 
 // mockProfileManager is an autogenerated mock type for the ProfileManager type
 // mockProfileManager is an autogenerated mock type for the ProfileManager type
 type mockProfileManager struct {
 type mockProfileManager struct {
@@ -18,7 +21,7 @@ func (_m *mockProfileManager) EXPECT() *mockProfileManager_Expecter {
 }
 }
 
 
 // Profile provides a mock function with given fields: screenName
 // Profile provides a mock function with given fields: screenName
-func (_m *mockProfileManager) Profile(screenName string) (string, error) {
+func (_m *mockProfileManager) Profile(screenName state.IdentScreenName) (string, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -27,16 +30,16 @@ func (_m *mockProfileManager) Profile(screenName string) (string, error) {
 
 
 	var r0 string
 	var r0 string
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (string, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) string); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) string); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		r0 = ret.Get(0).(string)
 		r0 = ret.Get(0).(string)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -51,14 +54,14 @@ type mockProfileManager_Profile_Call struct {
 }
 }
 
 
 // Profile is a helper method to define mock.On call
 // Profile is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockProfileManager_Expecter) Profile(screenName interface{}) *mockProfileManager_Profile_Call {
 func (_e *mockProfileManager_Expecter) Profile(screenName interface{}) *mockProfileManager_Profile_Call {
 	return &mockProfileManager_Profile_Call{Call: _e.mock.On("Profile", screenName)}
 	return &mockProfileManager_Profile_Call{Call: _e.mock.On("Profile", screenName)}
 }
 }
 
 
-func (_c *mockProfileManager_Profile_Call) Run(run func(screenName string)) *mockProfileManager_Profile_Call {
+func (_c *mockProfileManager_Profile_Call) Run(run func(screenName state.IdentScreenName)) *mockProfileManager_Profile_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -68,13 +71,13 @@ func (_c *mockProfileManager_Profile_Call) Return(_a0 string, _a1 error) *mockPr
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockProfileManager_Profile_Call) RunAndReturn(run func(string) (string, error)) *mockProfileManager_Profile_Call {
+func (_c *mockProfileManager_Profile_Call) RunAndReturn(run func(state.IdentScreenName) (string, error)) *mockProfileManager_Profile_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // SetProfile provides a mock function with given fields: screenName, body
 // SetProfile provides a mock function with given fields: screenName, body
-func (_m *mockProfileManager) SetProfile(screenName string, body string) error {
+func (_m *mockProfileManager) SetProfile(screenName state.IdentScreenName, body string) error {
 	ret := _m.Called(screenName, body)
 	ret := _m.Called(screenName, body)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -82,7 +85,7 @@ func (_m *mockProfileManager) SetProfile(screenName string, body string) error {
 	}
 	}
 
 
 	var r0 error
 	var r0 error
-	if rf, ok := ret.Get(0).(func(string, string) error); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName, string) error); ok {
 		r0 = rf(screenName, body)
 		r0 = rf(screenName, body)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
@@ -97,15 +100,15 @@ type mockProfileManager_SetProfile_Call struct {
 }
 }
 
 
 // SetProfile is a helper method to define mock.On call
 // SetProfile is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 //   - body string
 //   - body string
 func (_e *mockProfileManager_Expecter) SetProfile(screenName interface{}, body interface{}) *mockProfileManager_SetProfile_Call {
 func (_e *mockProfileManager_Expecter) SetProfile(screenName interface{}, body interface{}) *mockProfileManager_SetProfile_Call {
 	return &mockProfileManager_SetProfile_Call{Call: _e.mock.On("SetProfile", screenName, body)}
 	return &mockProfileManager_SetProfile_Call{Call: _e.mock.On("SetProfile", screenName, body)}
 }
 }
 
 
-func (_c *mockProfileManager_SetProfile_Call) Run(run func(screenName string, body string)) *mockProfileManager_SetProfile_Call {
+func (_c *mockProfileManager_SetProfile_Call) Run(run func(screenName state.IdentScreenName, body string)) *mockProfileManager_SetProfile_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].(string))
+		run(args[0].(state.IdentScreenName), args[1].(string))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -115,7 +118,7 @@ func (_c *mockProfileManager_SetProfile_Call) Return(_a0 error) *mockProfileMana
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockProfileManager_SetProfile_Call) RunAndReturn(run func(string, string) error) *mockProfileManager_SetProfile_Call {
+func (_c *mockProfileManager_SetProfile_Call) RunAndReturn(run func(state.IdentScreenName, string) error) *mockProfileManager_SetProfile_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 17 - 17
foodgroup/mock_session_manager_test.go

@@ -21,7 +21,7 @@ func (_m *mockSessionManager) EXPECT() *mockSessionManager_Expecter {
 }
 }
 
 
 // AddSession provides a mock function with given fields: screenName
 // AddSession provides a mock function with given fields: screenName
-func (_m *mockSessionManager) AddSession(screenName string) *state.Session {
+func (_m *mockSessionManager) AddSession(screenName state.DisplayScreenName) *state.Session {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -29,7 +29,7 @@ func (_m *mockSessionManager) AddSession(screenName string) *state.Session {
 	}
 	}
 
 
 	var r0 *state.Session
 	var r0 *state.Session
-	if rf, ok := ret.Get(0).(func(string) *state.Session); ok {
+	if rf, ok := ret.Get(0).(func(state.DisplayScreenName) *state.Session); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
@@ -46,14 +46,14 @@ type mockSessionManager_AddSession_Call struct {
 }
 }
 
 
 // AddSession is a helper method to define mock.On call
 // AddSession is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.DisplayScreenName
 func (_e *mockSessionManager_Expecter) AddSession(screenName interface{}) *mockSessionManager_AddSession_Call {
 func (_e *mockSessionManager_Expecter) AddSession(screenName interface{}) *mockSessionManager_AddSession_Call {
 	return &mockSessionManager_AddSession_Call{Call: _e.mock.On("AddSession", screenName)}
 	return &mockSessionManager_AddSession_Call{Call: _e.mock.On("AddSession", screenName)}
 }
 }
 
 
-func (_c *mockSessionManager_AddSession_Call) Run(run func(screenName string)) *mockSessionManager_AddSession_Call {
+func (_c *mockSessionManager_AddSession_Call) Run(run func(screenName state.DisplayScreenName)) *mockSessionManager_AddSession_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.DisplayScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -63,7 +63,7 @@ func (_c *mockSessionManager_AddSession_Call) Return(_a0 *state.Session) *mockSe
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockSessionManager_AddSession_Call) RunAndReturn(run func(string) *state.Session) *mockSessionManager_AddSession_Call {
+func (_c *mockSessionManager_AddSession_Call) RunAndReturn(run func(state.DisplayScreenName) *state.Session) *mockSessionManager_AddSession_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
@@ -146,17 +146,17 @@ func (_c *mockSessionManager_RemoveSession_Call) RunAndReturn(run func(*state.Se
 	return _c
 	return _c
 }
 }
 
 
-// RetrieveSession provides a mock function with given fields: ID
-func (_m *mockSessionManager) RetrieveSession(ID string) *state.Session {
-	ret := _m.Called(ID)
+// RetrieveSession provides a mock function with given fields: screenName
+func (_m *mockSessionManager) RetrieveSession(screenName state.IdentScreenName) *state.Session {
+	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for RetrieveSession")
 		panic("no return value specified for RetrieveSession")
 	}
 	}
 
 
 	var r0 *state.Session
 	var r0 *state.Session
-	if rf, ok := ret.Get(0).(func(string) *state.Session); ok {
-		r0 = rf(ID)
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.Session); ok {
+		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.Session)
 			r0 = ret.Get(0).(*state.Session)
@@ -172,14 +172,14 @@ type mockSessionManager_RetrieveSession_Call struct {
 }
 }
 
 
 // RetrieveSession is a helper method to define mock.On call
 // RetrieveSession is a helper method to define mock.On call
-//   - ID string
-func (_e *mockSessionManager_Expecter) RetrieveSession(ID interface{}) *mockSessionManager_RetrieveSession_Call {
-	return &mockSessionManager_RetrieveSession_Call{Call: _e.mock.On("RetrieveSession", ID)}
+//   - screenName state.IdentScreenName
+func (_e *mockSessionManager_Expecter) RetrieveSession(screenName interface{}) *mockSessionManager_RetrieveSession_Call {
+	return &mockSessionManager_RetrieveSession_Call{Call: _e.mock.On("RetrieveSession", screenName)}
 }
 }
 
 
-func (_c *mockSessionManager_RetrieveSession_Call) Run(run func(ID string)) *mockSessionManager_RetrieveSession_Call {
+func (_c *mockSessionManager_RetrieveSession_Call) Run(run func(screenName state.IdentScreenName)) *mockSessionManager_RetrieveSession_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -189,7 +189,7 @@ func (_c *mockSessionManager_RetrieveSession_Call) Return(_a0 *state.Session) *m
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockSessionManager_RetrieveSession_Call) RunAndReturn(run func(string) *state.Session) *mockSessionManager_RetrieveSession_Call {
+func (_c *mockSessionManager_RetrieveSession_Call) RunAndReturn(run func(state.IdentScreenName) *state.Session) *mockSessionManager_RetrieveSession_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 8 - 8
foodgroup/mock_user_manager_manager_test.go

@@ -67,7 +67,7 @@ func (_c *mockUserManager_InsertUser_Call) RunAndReturn(run func(state.User) err
 }
 }
 
 
 // User provides a mock function with given fields: screenName
 // User provides a mock function with given fields: screenName
-func (_m *mockUserManager) User(screenName string) (*state.User, error) {
+func (_m *mockUserManager) User(screenName state.IdentScreenName) (*state.User, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -76,10 +76,10 @@ func (_m *mockUserManager) User(screenName string) (*state.User, error) {
 
 
 	var r0 *state.User
 	var r0 *state.User
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (*state.User, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) *state.User); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
@@ -87,7 +87,7 @@ func (_m *mockUserManager) User(screenName string) (*state.User, error) {
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -102,14 +102,14 @@ type mockUserManager_User_Call struct {
 }
 }
 
 
 // User is a helper method to define mock.On call
 // User is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockUserManager_Expecter) User(screenName interface{}) *mockUserManager_User_Call {
 func (_e *mockUserManager_Expecter) User(screenName interface{}) *mockUserManager_User_Call {
 	return &mockUserManager_User_Call{Call: _e.mock.On("User", screenName)}
 	return &mockUserManager_User_Call{Call: _e.mock.On("User", screenName)}
 }
 }
 
 
-func (_c *mockUserManager_User_Call) Run(run func(screenName string)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) Run(run func(screenName state.IdentScreenName)) *mockUserManager_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -119,7 +119,7 @@ func (_c *mockUserManager_User_Call) Return(_a0 *state.User, _a1 error) *mockUse
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockUserManager_User_Call) RunAndReturn(run func(string) (*state.User, error)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockUserManager_User_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 5 - 5
foodgroup/oservice.go

@@ -562,7 +562,7 @@ type chatLoginCookie struct {
 func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x01_0x04_OServiceServiceRequest) (wire.SNACMessage, error) {
 func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x01_0x04_OServiceServiceRequest) (wire.SNACMessage, error) {
 	switch inBody.FoodGroup {
 	switch inBody.FoodGroup {
 	case wire.Alert:
 	case wire.Alert:
-		cookie, err := s.cookieIssuer.Issue([]byte(sess.ScreenName()))
+		cookie, err := s.cookieIssuer.Issue([]byte(sess.IdentScreenName().String()))
 		if err != nil {
 		if err != nil {
 			return wire.SNACMessage{}, err
 			return wire.SNACMessage{}, err
 		}
 		}
@@ -585,7 +585,7 @@ func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.S
 			},
 			},
 		}, nil
 		}, nil
 	case wire.BART:
 	case wire.BART:
-		cookie, err := s.cookieIssuer.Issue([]byte(sess.ScreenName()))
+		cookie, err := s.cookieIssuer.Issue([]byte(sess.IdentScreenName().String()))
 		if err != nil {
 		if err != nil {
 			return wire.SNACMessage{}, err
 			return wire.SNACMessage{}, err
 		}
 		}
@@ -608,7 +608,7 @@ func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.S
 			},
 			},
 		}, nil
 		}, nil
 	case wire.ChatNav:
 	case wire.ChatNav:
-		cookie, err := s.cookieIssuer.Issue([]byte(sess.ScreenName()))
+		cookie, err := s.cookieIssuer.Issue([]byte(sess.IdentScreenName().String()))
 		if err != nil {
 		if err != nil {
 			return wire.SNACMessage{}, err
 			return wire.SNACMessage{}, err
 		}
 		}
@@ -648,7 +648,7 @@ func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.S
 
 
 		loginCookie := chatLoginCookie{
 		loginCookie := chatLoginCookie{
 			ChatCookie: room.Cookie,
 			ChatCookie: room.Cookie,
-			ScreenName: sess.ScreenName(),
+			ScreenName: sess.IdentScreenName().String(),
 		}
 		}
 		buf := &bytes.Buffer{}
 		buf := &bytes.Buffer{}
 		if err := wire.Marshal(loginCookie, buf); err != nil {
 		if err := wire.Marshal(loginCookie, buf); err != nil {
@@ -703,7 +703,7 @@ func (s OServiceServiceForBOS) ClientOnline(ctx context.Context, _ wire.SNAC_0x0
 	}
 	}
 
 
 	// send buddy arrival events to client-side buddy list
 	// send buddy arrival events to client-side buddy list
-	buddies := s.legacyBuddyListManager.Buddies(sess.ScreenName())
+	buddies := s.legacyBuddyListManager.Buddies(sess.IdentScreenName())
 	for _, buddy := range buddies {
 	for _, buddy := range buddies {
 		buddySess := s.messageRelayer.RetrieveByScreenName(buddy)
 		buddySess := s.messageRelayer.RetrieveByScreenName(buddy)
 		if buddySess == nil || buddySess.Invisible() {
 		if buddySess == nil || buddySess.Invisible() {

+ 36 - 30
foodgroup/oservice_test.go

@@ -245,7 +245,7 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) {
 			chatSess := &state.Session{}
 			chatSess := &state.Session{}
 			if tc.chatRoom != nil {
 			if tc.chatRoom != nil {
 				sessionManager.EXPECT().
 				sessionManager.EXPECT().
-					AddSession(tc.userSession.ScreenName()).
+					AddSession(tc.userSession.IdentScreenName()).
 					Return(chatSess).
 					Return(chatSess).
 					Maybe()
 					Maybe()
 				chatRegistry.Register(*tc.chatRoom, sessionManager)
 				chatRegistry.Register(*tc.chatRoom, sessionManager)
@@ -329,7 +329,7 @@ func TestSetUserInfoFields(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -364,7 +364,7 @@ func TestSetUserInfoFields(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
 					broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
 						{
 						{
-							screenName: "user_screen_name",
+							screenName: state.NewIdentScreenName("user_screen_name"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -379,7 +379,7 @@ func TestSetUserInfoFields(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -387,7 +387,7 @@ func TestSetUserInfoFields(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyDeparted(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyDeparted(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -1452,7 +1452,7 @@ func TestOServiceService_IdleNotification(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "test-user",
+							screenName: state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1468,7 +1468,7 @@ func TestOServiceService_IdleNotification(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "test-user",
+							screenName: state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1482,7 +1482,7 @@ func TestOServiceService_IdleNotification(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -1522,19 +1522,22 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					legacyBuddiesParams: legacyBuddiesParams{
 					legacyBuddiesParams: legacyBuddiesParams{
 						{
 						{
-							userScreenName: "test-user",
-							result:         []string{"buddy1", "buddy2"},
+							userScreenName: state.NewIdentScreenName("test-user"),
+							result: []state.IdentScreenName{
+								state.NewIdentScreenName("buddy1"),
+								state.NewIdentScreenName("buddy2"),
+							},
 						},
 						},
 					},
 					},
 				},
 				},
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy1",
+							screenName: state.NewIdentScreenName("buddy1"),
 							sess:       newTestSession("buddy1", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy1", sessOptCannedSignonTime),
 						},
 						},
 						{
 						{
-							screenName: "buddy2",
+							screenName: state.NewIdentScreenName("buddy2"),
 							sess:       newTestSession("buddy2", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy2", sessOptCannedSignonTime),
 						},
 						},
 					},
 					},
@@ -1542,17 +1545,17 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "test-user",
+							screenName: state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 						{
 						{
-							from: "buddy1",
-							to:   "test-user",
+							from: state.NewIdentScreenName("buddy1"),
+							to:   state.NewIdentScreenName("test-user"),
 						},
 						},
 						{
 						{
-							from: "buddy2",
-							to:   "test-user",
+							from: state.NewIdentScreenName("buddy2"),
+							to:   state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1566,19 +1569,22 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 				legacyBuddyListManagerParams: legacyBuddyListManagerParams{
 					legacyBuddiesParams: legacyBuddiesParams{
 					legacyBuddiesParams: legacyBuddiesParams{
 						{
 						{
-							userScreenName: "test-user",
-							result:         []string{"buddy1", "buddy2"},
+							userScreenName: state.NewIdentScreenName("test-user"),
+							result: []state.IdentScreenName{
+								state.NewIdentScreenName("buddy1"),
+								state.NewIdentScreenName("buddy2"),
+							},
 						},
 						},
 					},
 					},
 				},
 				},
 				messageRelayerParams: messageRelayerParams{
 				messageRelayerParams: messageRelayerParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 					retrieveByScreenNameParams: retrieveByScreenNameParams{
 						{
 						{
-							screenName: "buddy1",
+							screenName: state.NewIdentScreenName("buddy1"),
 							sess:       newTestSession("buddy1", sessOptCannedSignonTime, sessOptInvisible),
 							sess:       newTestSession("buddy1", sessOptCannedSignonTime, sessOptInvisible),
 						},
 						},
 						{
 						{
-							screenName: "buddy2",
+							screenName: state.NewIdentScreenName("buddy2"),
 							sess:       newTestSession("buddy2", sessOptCannedSignonTime),
 							sess:       newTestSession("buddy2", sessOptCannedSignonTime),
 						},
 						},
 					},
 					},
@@ -1586,13 +1592,13 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 				buddyBroadcasterParams: buddyBroadcasterParams{
 				buddyBroadcasterParams: buddyBroadcasterParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
 						{
 						{
-							screenName: "test-user",
+							screenName: state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 					unicastBuddyArrivedParams: unicastBuddyArrivedParams{
 						{
 						{
-							from: "buddy2",
-							to:   "test-user",
+							from: state.NewIdentScreenName("buddy2"),
+							to:   state.NewIdentScreenName("test-user"),
 						},
 						},
 					},
 					},
 				},
 				},
@@ -1618,7 +1624,7 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 				p := params
 				p := params
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
-						return s.ScreenName() == p.screenName
+						return s.IdentScreenName() == p.screenName
 					})).
 					})).
 					Return(nil)
 					Return(nil)
 			}
 			}
@@ -1627,10 +1633,10 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 				buddyUpdateBroadcaster.EXPECT().
 				buddyUpdateBroadcaster.EXPECT().
 					UnicastBuddyArrived(mock.Anything,
 					UnicastBuddyArrived(mock.Anything,
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.from
+							return s.IdentScreenName() == p.from
 						}),
 						}),
 						mock.MatchedBy(func(s *state.Session) bool {
 						mock.MatchedBy(func(s *state.Session) bool {
-							return s.ScreenName() == p.to
+							return s.IdentScreenName() == p.to
 						})).
 						})).
 					Return(p.err)
 					Return(p.err)
 			}
 			}
@@ -1659,7 +1665,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 		message wire.SNACMessage
 		message wire.SNACMessage
 	}
 	}
 	type sendToScreenNameParams []struct {
 	type sendToScreenNameParams []struct {
-		screenName string
+		screenName state.IdentScreenName
 		message    wire.SNACMessage
 		message    wire.SNACMessage
 	}
 	}
 
 
@@ -1710,7 +1716,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 			},
 			},
 			sendToScreenNameParams: sendToScreenNameParams{
 			sendToScreenNameParams: sendToScreenNameParams{
 				{
 				{
-					screenName: chatter1.ScreenName(),
+					screenName: chatter1.IdentScreenName(),
 					message: wire.SNACMessage{
 					message: wire.SNACMessage{
 						Frame: wire.SNACFrame{
 						Frame: wire.SNACFrame{
 							FoodGroup: wire.Chat,
 							FoodGroup: wire.Chat,
@@ -1728,7 +1734,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 					},
 					},
 				},
 				},
 				{
 				{
-					screenName: chatter1.ScreenName(),
+					screenName: chatter1.IdentScreenName(),
 					message: wire.SNACMessage{
 					message: wire.SNACMessage{
 						Frame: wire.SNACFrame{
 						Frame: wire.SNACFrame{
 							FoodGroup: wire.Chat,
 							FoodGroup: wire.Chat,

+ 37 - 37
foodgroup/test_helpers.go

@@ -69,7 +69,7 @@ type userManagerParams struct {
 // getUserParams is the list of parameters passed at the mock
 // getUserParams is the list of parameters passed at the mock
 // UserManager.User call site
 // UserManager.User call site
 type getUserParams []struct {
 type getUserParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	result     *state.User
 	result     *state.User
 	err        error
 	err        error
 }
 }
@@ -92,8 +92,7 @@ type sessionManagerParams struct {
 // addSessionParams is the list of parameters passed at the mock
 // addSessionParams is the list of parameters passed at the mock
 // SessionManager.AddSession call site
 // SessionManager.AddSession call site
 type addSessionParams []struct {
 type addSessionParams []struct {
-	sessID     string
-	screenName string
+	screenName state.DisplayScreenName
 	result     *state.Session
 	result     *state.Session
 }
 }
 
 
@@ -124,8 +123,8 @@ type feedbagManagerParams struct {
 // blockedStateParams is the list of parameters passed at the mock
 // blockedStateParams is the list of parameters passed at the mock
 // FeedbagManager.BlockedState call site
 // FeedbagManager.BlockedState call site
 type blockedStateParams []struct {
 type blockedStateParams []struct {
-	screenName1 string
-	screenName2 string
+	screenName1 state.IdentScreenName
+	screenName2 state.IdentScreenName
 	result      state.BlockedState
 	result      state.BlockedState
 	err         error
 	err         error
 }
 }
@@ -133,43 +132,43 @@ type blockedStateParams []struct {
 // adjacentUsersParams is the list of parameters passed at the mock
 // adjacentUsersParams is the list of parameters passed at the mock
 // FeedbagManager.AdjacentUsers call site
 // FeedbagManager.AdjacentUsers call site
 type adjacentUsersParams []struct {
 type adjacentUsersParams []struct {
-	screenName string
-	users      []string
+	screenName state.IdentScreenName
+	users      []state.IdentScreenName
 	err        error
 	err        error
 }
 }
 
 
 // feedbagUpsertParams is the list of parameters passed at the mock
 // feedbagUpsertParams is the list of parameters passed at the mock
 // FeedbagManager.FeedbagUpsert call site
 // FeedbagManager.FeedbagUpsert call site
 type feedbagUpsertParams []struct {
 type feedbagUpsertParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	items      []wire.FeedbagItem
 	items      []wire.FeedbagItem
 }
 }
 
 
 // buddiesParams is the list of parameters passed at the mock
 // buddiesParams is the list of parameters passed at the mock
 // FeedbagManager.Buddies call site
 // FeedbagManager.Buddies call site
 type buddiesParams []struct {
 type buddiesParams []struct {
-	screenName string
-	results    []string
+	screenName state.IdentScreenName
+	results    []state.IdentScreenName
 }
 }
 
 
 // feedbagParams is the list of parameters passed at the mock
 // feedbagParams is the list of parameters passed at the mock
 // FeedbagManager.Feedbag call site
 // FeedbagManager.Feedbag call site
 type feedbagParams []struct {
 type feedbagParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	results    []wire.FeedbagItem
 	results    []wire.FeedbagItem
 }
 }
 
 
 // feedbagLastModifiedParams is the list of parameters passed at the mock
 // feedbagLastModifiedParams is the list of parameters passed at the mock
 // FeedbagManager.FeedbagLastModified call site
 // FeedbagManager.FeedbagLastModified call site
 type feedbagLastModifiedParams []struct {
 type feedbagLastModifiedParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	result     time.Time
 	result     time.Time
 }
 }
 
 
 // feedbagDeleteParams is the list of parameters passed at the mock
 // feedbagDeleteParams is the list of parameters passed at the mock
 // FeedbagManager.FeedbagDelete call site
 // FeedbagManager.FeedbagDelete call site
 type feedbagDeleteParams []struct {
 type feedbagDeleteParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	items      []wire.FeedbagItem
 	items      []wire.FeedbagItem
 }
 }
 
 
@@ -184,21 +183,21 @@ type messageRelayerParams struct {
 // retrieveByScreenNameParams is the list of parameters passed at the mock
 // retrieveByScreenNameParams is the list of parameters passed at the mock
 // MessageRelayer.RetrieveByScreenName call site
 // MessageRelayer.RetrieveByScreenName call site
 type retrieveByScreenNameParams []struct {
 type retrieveByScreenNameParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	sess       *state.Session
 	sess       *state.Session
 }
 }
 
 
 // relayToScreenNamesParams is the list of parameters passed at the mock
 // relayToScreenNamesParams is the list of parameters passed at the mock
 // MessageRelayer.RelayToScreenNames call site
 // MessageRelayer.RelayToScreenNames call site
 type relayToScreenNamesParams []struct {
 type relayToScreenNamesParams []struct {
-	screenNames []string
+	screenNames []state.IdentScreenName
 	message     wire.SNACMessage
 	message     wire.SNACMessage
 }
 }
 
 
 // relayToScreenNameParams is the list of parameters passed at the mock
 // relayToScreenNameParams is the list of parameters passed at the mock
 // MessageRelayer.RelayToScreenName call site
 // MessageRelayer.RelayToScreenName call site
 type relayToScreenNameParams []struct {
 type relayToScreenNameParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	message    wire.SNACMessage
 	message    wire.SNACMessage
 }
 }
 
 
@@ -210,17 +209,17 @@ type profileManagerParams struct {
 }
 }
 
 
 // retrieveByScreenNameParams is the list of parameters passed at the mock
 // retrieveByScreenNameParams is the list of parameters passed at the mock
-// ProfileManager.RetrieveProfile call site
+// ProfileManager.Profile call site
 type retrieveProfileParams []struct {
 type retrieveProfileParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	result     string
 	result     string
 	err        error
 	err        error
 }
 }
 
 
 // setProfileParams is the list of parameters passed at the mock
 // setProfileParams is the list of parameters passed at the mock
-// ProfileManager.UpsertProfile call site
+// ProfileManager.SetProfile call site
 type setProfileParams []struct {
 type setProfileParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	body       any
 	body       any
 }
 }
 
 
@@ -250,35 +249,35 @@ type legacyBuddyListManagerParams struct {
 // legacyBuddiesParams is the list of parameters passed at the mock
 // legacyBuddiesParams is the list of parameters passed at the mock
 // LegacyBuddyListManager.AddBuddy call site
 // LegacyBuddyListManager.AddBuddy call site
 type addBuddyParams []struct {
 type addBuddyParams []struct {
-	userScreenName  string
-	buddyScreenName string
+	userScreenName  state.IdentScreenName
+	buddyScreenName state.IdentScreenName
 }
 }
 
 
 // legacyBuddiesParams is the list of parameters passed at the mock
 // legacyBuddiesParams is the list of parameters passed at the mock
 // LegacyBuddyListManager.DeleteBuddy call site
 // LegacyBuddyListManager.DeleteBuddy call site
 type deleteBuddyParams []struct {
 type deleteBuddyParams []struct {
-	userScreenName  string
-	buddyScreenName string
+	userScreenName  state.IdentScreenName
+	buddyScreenName state.IdentScreenName
 }
 }
 
 
 // deleteUserParams is the list of parameters passed at the mock
 // deleteUserParams is the list of parameters passed at the mock
 // LegacyBuddyListManager.DeleteUser call site
 // LegacyBuddyListManager.DeleteUser call site
 type deleteUserParams []struct {
 type deleteUserParams []struct {
-	userScreenName string
+	userScreenName state.IdentScreenName
 }
 }
 
 
 // legacyBuddiesParams is the list of parameters passed at the mock
 // legacyBuddiesParams is the list of parameters passed at the mock
 // LegacyBuddyListManager.Buddies call site
 // LegacyBuddyListManager.Buddies call site
 type legacyBuddiesParams []struct {
 type legacyBuddiesParams []struct {
-	userScreenName string
-	result         []string
+	userScreenName state.IdentScreenName
+	result         []state.IdentScreenName
 }
 }
 
 
 // whoAddedUserParams is the list of parameters passed at the mock
 // whoAddedUserParams is the list of parameters passed at the mock
 // LegacyBuddyListManager.WhoAddedUser call site
 // LegacyBuddyListManager.WhoAddedUser call site
 type whoAddedUserParams []struct {
 type whoAddedUserParams []struct {
-	userScreenName string
-	result         []string
+	userScreenName state.IdentScreenName
+	result         []state.IdentScreenName
 }
 }
 
 
 // cookieIssuerParams is the list of parameters passed at the mock
 // cookieIssuerParams is the list of parameters passed at the mock
@@ -301,30 +300,30 @@ type buddyBroadcasterParams struct {
 // broadcastBuddyArrivedParams is the list of parameters passed at the mock
 // broadcastBuddyArrivedParams is the list of parameters passed at the mock
 // BuddyBroadcaster.BroadcastBuddyArrived call site
 // BuddyBroadcaster.BroadcastBuddyArrived call site
 type broadcastBuddyArrivedParams []struct {
 type broadcastBuddyArrivedParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	err        error
 	err        error
 }
 }
 
 
 // broadcastBuddyDepartedParams is the list of parameters passed at the mock
 // broadcastBuddyDepartedParams is the list of parameters passed at the mock
 // BuddyBroadcaster.BroadcastBuddyDeparted call site
 // BuddyBroadcaster.BroadcastBuddyDeparted call site
 type broadcastBuddyDepartedParams []struct {
 type broadcastBuddyDepartedParams []struct {
-	screenName string
+	screenName state.IdentScreenName
 	err        error
 	err        error
 }
 }
 
 
 // unicastBuddyArrivedParams is the list of parameters passed at the mock
 // unicastBuddyArrivedParams is the list of parameters passed at the mock
 // BuddyBroadcaster.UnicastBuddyArrived call site
 // BuddyBroadcaster.UnicastBuddyArrived call site
 type unicastBuddyArrivedParams []struct {
 type unicastBuddyArrivedParams []struct {
-	from string
-	to   string
+	from state.IdentScreenName
+	to   state.IdentScreenName
 	err  error
 	err  error
 }
 }
 
 
 // unicastBuddyDepartedParams is the list of parameters passed at the mock
 // unicastBuddyDepartedParams is the list of parameters passed at the mock
 // BuddyBroadcaster.UnicastBuddyDeparted call site
 // BuddyBroadcaster.UnicastBuddyDeparted call site
 type unicastBuddyDepartedParams []struct {
 type unicastBuddyDepartedParams []struct {
-	from string
-	to   string
+	from state.IdentScreenName
+	to   state.IdentScreenName
 	err  error
 	err  error
 }
 }
 
 
@@ -388,9 +387,10 @@ func sessOptCaps(caps [][16]byte) func(session *state.Session) {
 
 
 // newTestSession creates a session object with 0 or more functional options
 // newTestSession creates a session object with 0 or more functional options
 // applied
 // applied
-func newTestSession(screenName string, options ...func(session *state.Session)) *state.Session {
+func newTestSession(screenName state.DisplayScreenName, options ...func(session *state.Session)) *state.Session {
 	s := state.NewSession()
 	s := state.NewSession()
-	s.SetScreenName(screenName)
+	s.SetIdentScreenName(screenName.IdentScreenName())
+	s.SetDisplayScreenName(screenName)
 	for _, op := range options {
 	for _, op := range options {
 		op(s)
 		op(s)
 	}
 	}

+ 20 - 20
foodgroup/types.go

@@ -42,13 +42,13 @@ import (
 )
 )
 
 
 type FeedbagManager interface {
 type FeedbagManager interface {
-	BlockedState(screenName1, screenName2 string) (state.BlockedState, error)
-	Buddies(screenName string) ([]string, error)
-	FeedbagDelete(screenName string, items []wire.FeedbagItem) error
-	AdjacentUsers(screenName string) ([]string, error)
-	FeedbagLastModified(screenName string) (time.Time, error)
-	Feedbag(screenName string) ([]wire.FeedbagItem, error)
-	FeedbagUpsert(screenName string, items []wire.FeedbagItem) error
+	BlockedState(screenName1, screenName2 state.IdentScreenName) (state.BlockedState, error)
+	Buddies(screenName state.IdentScreenName) ([]state.IdentScreenName, error)
+	FeedbagDelete(screenName state.IdentScreenName, items []wire.FeedbagItem) error
+	AdjacentUsers(screenName state.IdentScreenName) ([]state.IdentScreenName, error)
+	FeedbagLastModified(screenName state.IdentScreenName) (time.Time, error)
+	Feedbag(screenName state.IdentScreenName) ([]wire.FeedbagItem, error)
+	FeedbagUpsert(screenName state.IdentScreenName, items []wire.FeedbagItem) error
 }
 }
 
 
 // LegacyBuddyListManager defines operations for tracking user relationships
 // LegacyBuddyListManager defines operations for tracking user relationships
@@ -56,44 +56,44 @@ type FeedbagManager interface {
 // 4.3.
 // 4.3.
 type LegacyBuddyListManager interface {
 type LegacyBuddyListManager interface {
 	// AddBuddy adds buddyScreenName to userScreenName's buddy list.
 	// AddBuddy adds buddyScreenName to userScreenName's buddy list.
-	AddBuddy(userScreenName, buddyScreenName string)
+	AddBuddy(userScreenName, buddyScreenName state.IdentScreenName)
 
 
 	// Buddies returns a list of all buddies associated with the specified
 	// Buddies returns a list of all buddies associated with the specified
 	// userScreenName.
 	// userScreenName.
-	Buddies(userScreenName string) []string
+	Buddies(userScreenName state.IdentScreenName) []state.IdentScreenName
 
 
 	// DeleteBuddy removes buddyScreenName from userScreenName's buddy list.
 	// DeleteBuddy removes buddyScreenName from userScreenName's buddy list.
-	DeleteBuddy(userScreenName, buddyScreenName string)
+	DeleteBuddy(userScreenName, buddyScreenName state.IdentScreenName)
 
 
 	// DeleteUser removes userScreenName's buddy list.
 	// DeleteUser removes userScreenName's buddy list.
-	DeleteUser(userScreenName string)
+	DeleteUser(userScreenName state.IdentScreenName)
 
 
 	// WhoAddedUser returns a list of screen names who have userScreenName in
 	// WhoAddedUser returns a list of screen names who have userScreenName in
 	// their buddy lists.
 	// their buddy lists.
-	WhoAddedUser(userScreenName string) []string
+	WhoAddedUser(userScreenName state.IdentScreenName) []state.IdentScreenName
 }
 }
 
 
 type UserManager interface {
 type UserManager interface {
-	User(screenName string) (*state.User, error)
+	User(screenName state.IdentScreenName) (*state.User, error)
 	InsertUser(u state.User) error
 	InsertUser(u state.User) error
 }
 }
 
 
 type SessionManager interface {
 type SessionManager interface {
 	Empty() bool
 	Empty() bool
-	AddSession(screenName string) *state.Session
+	AddSession(screenName state.DisplayScreenName) *state.Session
 	RemoveSession(sess *state.Session)
 	RemoveSession(sess *state.Session)
-	RetrieveSession(ID string) *state.Session
+	RetrieveSession(screenName state.IdentScreenName) *state.Session
 }
 }
 
 
 type ProfileManager interface {
 type ProfileManager interface {
-	Profile(screenName string) (string, error)
-	SetProfile(screenName string, body string) error
+	Profile(screenName state.IdentScreenName) (string, error)
+	SetProfile(screenName state.IdentScreenName, body string) error
 }
 }
 
 
 type MessageRelayer interface {
 type MessageRelayer interface {
-	RelayToScreenNames(ctx context.Context, screenNames []string, msg wire.SNACMessage)
-	RetrieveByScreenName(screenName string) *state.Session
-	RelayToScreenName(ctx context.Context, screenName string, msg wire.SNACMessage)
+	RelayToScreenNames(ctx context.Context, screenNames []state.IdentScreenName, msg wire.SNACMessage)
+	RetrieveByScreenName(screenName state.IdentScreenName) *state.Session
+	RelayToScreenName(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage)
 }
 }
 
 
 type ChatMessageRelayer interface {
 type ChatMessageRelayer interface {

+ 38 - 54
server/http/mgmt_api.go

@@ -34,10 +34,10 @@ type onlineUsers struct {
 
 
 type UserManager interface {
 type UserManager interface {
 	AllUsers() ([]state.User, error)
 	AllUsers() ([]state.User, error)
-	DeleteUser(screenName string) error
+	DeleteUser(screenName state.IdentScreenName) error
 	InsertUser(u state.User) error
 	InsertUser(u state.User) error
 	SetUserPassword(u state.User) error
 	SetUserPassword(u state.User) error
-	User(screenName string) (*state.User, error)
+	User(screenName state.IdentScreenName) (*state.User, error)
 }
 }
 
 
 type SessionRetriever interface {
 type SessionRetriever interface {
@@ -46,14 +46,11 @@ type SessionRetriever interface {
 
 
 func StartManagementAPI(cfg config.Config, userManager UserManager, sessionRetriever SessionRetriever, logger *slog.Logger) {
 func StartManagementAPI(cfg config.Config, userManager UserManager, sessionRetriever SessionRetriever, logger *slog.Logger) {
 	mux := http.NewServeMux()
 	mux := http.NewServeMux()
-	newUser := func() state.User {
-		return state.User{AuthKey: uuid.New().String()}
-	}
 	mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
 	mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
-		userHandler(w, r, userManager, newUser, logger)
+		userHandler(w, r, userManager, uuid.New, logger)
 	})
 	})
 	mux.HandleFunc("/user/password", func(w http.ResponseWriter, r *http.Request) {
 	mux.HandleFunc("/user/password", func(w http.ResponseWriter, r *http.Request) {
-		userPasswordHandler(w, r, userManager, newUser, logger)
+		userPasswordHandler(w, r, userManager, uuid.New, logger)
 	})
 	})
 	mux.HandleFunc("/user/login", func(w http.ResponseWriter, r *http.Request) {
 	mux.HandleFunc("/user/login", func(w http.ResponseWriter, r *http.Request) {
 		loginHandler(w, r, userManager, logger)
 		loginHandler(w, r, userManager, logger)
@@ -70,32 +67,27 @@ func StartManagementAPI(cfg config.Config, userManager UserManager, sessionRetri
 	}
 	}
 }
 }
 
 
-func userHandler(
-	w http.ResponseWriter,
-	r *http.Request,
-	userManager UserManager,
-	newUser func() state.User,
-	logger *slog.Logger,
-) {
+func userHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, newUUID func() uuid.UUID, logger *slog.Logger) {
 	switch r.Method {
 	switch r.Method {
 	case http.MethodDelete:
 	case http.MethodDelete:
 		deleteUserHandler(w, r, userManager, logger)
 		deleteUserHandler(w, r, userManager, logger)
 	case http.MethodGet:
 	case http.MethodGet:
 		getUserHandler(w, r, userManager, logger)
 		getUserHandler(w, r, userManager, logger)
 	case http.MethodPost:
 	case http.MethodPost:
-		postUserHandler(w, r, userManager, newUser, logger)
+		postUserHandler(w, r, userManager, newUUID, logger)
 	default:
 	default:
 		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
 		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
 	}
 	}
 }
 }
 
 
 func deleteUserHandler(w http.ResponseWriter, r *http.Request, manager UserManager, logger *slog.Logger) {
 func deleteUserHandler(w http.ResponseWriter, r *http.Request, manager UserManager, logger *slog.Logger) {
-	user := state.User{}
-	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
-		http.Error(w, "malformed input", http.StatusBadRequest)
+	user, err := userFromBody(r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 		return
 	}
 	}
-	err := manager.DeleteUser(user.ScreenName)
+
+	err = manager.DeleteUser(user.DisplayScreenName.IdentScreenName())
 	switch {
 	switch {
 	case errors.Is(err, state.ErrNoUser):
 	case errors.Is(err, state.ErrNoUser):
 		http.Error(w, "user does not exist", http.StatusNotFound)
 		http.Error(w, "user does not exist", http.StatusNotFound)
@@ -110,36 +102,25 @@ func deleteUserHandler(w http.ResponseWriter, r *http.Request, manager UserManag
 	fmt.Fprintln(w, "User account successfully deleted.")
 	fmt.Fprintln(w, "User account successfully deleted.")
 }
 }
 
 
-func userPasswordHandler(
-	w http.ResponseWriter,
-	r *http.Request,
-	userManager UserManager,
-	userFactory func() state.User,
-	logger *slog.Logger,
-) {
+func userPasswordHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, newUUID func() uuid.UUID, logger *slog.Logger) {
 	switch r.Method {
 	switch r.Method {
 	case http.MethodPut:
 	case http.MethodPut:
-		putUserPasswordHandler(w, r, userManager, userFactory, logger)
+		putUserPasswordHandler(w, r, userManager, newUUID, logger)
 	default:
 	default:
 		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
 		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
 	}
 	}
 }
 }
 
 
 // putUserPasswordHandler handles the PUT /user/password endpoint.
 // putUserPasswordHandler handles the PUT /user/password endpoint.
-func putUserPasswordHandler(
-	w http.ResponseWriter,
-	r *http.Request,
-	userManager UserManager,
-	newUser func() state.User,
-	logger *slog.Logger,
-) {
-	user := userWithPassword{
-		User: newUser(),
-	}
-	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
-		http.Error(w, "malformed input", http.StatusBadRequest)
+func putUserPasswordHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, newUUID func() uuid.UUID, logger *slog.Logger) {
+	user, err := userFromBody(r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 		return
 	}
 	}
+	user.AuthKey = newUUID().String()
+
+	user.IdentScreenName = user.DisplayScreenName.IdentScreenName()
 	if err := user.HashPassword(user.Password); err != nil {
 	if err := user.HashPassword(user.Password); err != nil {
 		logger.Error("error hashing user password in PUT /user/password", "err", err.Error())
 		logger.Error("error hashing user password in PUT /user/password", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -178,7 +159,7 @@ func sessionHandler(w http.ResponseWriter, r *http.Request, sessionRetriever Ses
 
 
 	for _, s := range allUsers {
 	for _, s := range allUsers {
 		ou.Sessions = append(ou.Sessions, userSession{
 		ou.Sessions = append(ou.Sessions, userSession{
-			ScreenName: s.ScreenName(),
+			ScreenName: s.DisplayScreenName().String(),
 		})
 		})
 	}
 	}
 
 
@@ -204,27 +185,21 @@ func getUserHandler(w http.ResponseWriter, _ *http.Request, userManager UserMana
 }
 }
 
 
 // postUserHandler handles the POST /user endpoint.
 // postUserHandler handles the POST /user endpoint.
-func postUserHandler(
-	w http.ResponseWriter,
-	r *http.Request,
-	userManager UserManager,
-	newUser func() state.User,
-	logger *slog.Logger,
-) {
-	user := userWithPassword{
-		User: newUser(),
-	}
-	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
-		http.Error(w, "malformed input", http.StatusBadRequest)
+func postUserHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, newUUID func() uuid.UUID, logger *slog.Logger) {
+	user, err := userFromBody(r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 		return
 	}
 	}
+	user.AuthKey = newUUID().String()
+
 	if err := user.HashPassword(user.Password); err != nil {
 	if err := user.HashPassword(user.Password); err != nil {
 		logger.Error("error hashing user password in POST /user", "err", err.Error())
 		logger.Error("error hashing user password in POST /user", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
 		http.Error(w, "internal server error", http.StatusInternalServerError)
 		return
 		return
 	}
 	}
 
 
-	err := userManager.InsertUser(user.User)
+	err = userManager.InsertUser(user.User)
 	switch {
 	switch {
 	case errors.Is(err, state.ErrDupUser):
 	case errors.Is(err, state.ErrDupUser):
 		http.Error(w, "user already exists", http.StatusConflict)
 		http.Error(w, "user already exists", http.StatusConflict)
@@ -239,6 +214,15 @@ func postUserHandler(
 	fmt.Fprintln(w, "User account created successfully.")
 	fmt.Fprintln(w, "User account created successfully.")
 }
 }
 
 
+func userFromBody(r *http.Request) (userWithPassword, error) {
+	user := userWithPassword{}
+	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
+		return userWithPassword{}, errors.New("malformed input")
+	}
+	user.IdentScreenName = user.DisplayScreenName.IdentScreenName()
+	return user, nil
+}
+
 // loginHandler is a temporary endpoint for validating user credentials for
 // loginHandler is a temporary endpoint for validating user credentials for
 // chivanet. do not rely on this endpoint, as it will be eventually removed.
 // chivanet. do not rely on this endpoint, as it will be eventually removed.
 func loginHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, logger *slog.Logger) {
 func loginHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, logger *slog.Logger) {
@@ -272,7 +256,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request, userManager UserManage
 		return
 		return
 	}
 	}
 
 
-	username, password := pair[0], pair[1]
+	username, password := state.NewIdentScreenName(pair[0]), pair[1]
 
 
 	user, err := userManager.User(username)
 	user, err := userManager.User(username)
 	if err != nil {
 	if err != nil {

+ 48 - 30
server/http/mgmt_api_test.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/google/uuid"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 
 
 	"github.com/mk6i/retro-aim-server/state"
 	"github.com/mk6i/retro-aim-server/state"
@@ -16,7 +17,8 @@ import (
 func TestSessionHandler_GET(t *testing.T) {
 func TestSessionHandler_GET(t *testing.T) {
 	fnNewSess := func(screenName string) *state.Session {
 	fnNewSess := func(screenName string) *state.Session {
 		sess := state.NewSession()
 		sess := state.NewSession()
-		sess.SetScreenName(screenName)
+		sess.SetIdentScreenName(state.NewIdentScreenName(screenName))
+		sess.SetDisplayScreenName(state.DisplayScreenName(screenName))
 		return sess
 		return sess
 	}
 	}
 	tt := []struct {
 	tt := []struct {
@@ -100,8 +102,14 @@ func TestUserHandler_GET(t *testing.T) {
 		{
 		{
 			name: "user store containing 2 users",
 			name: "user store containing 2 users",
 			users: []state.User{
 			users: []state.User{
-				{ScreenName: "userA"},
-				{ScreenName: "userB"},
+				{
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
+				},
+				{
+					DisplayScreenName: "userB",
+					IdentScreenName:   state.NewIdentScreenName("userB"),
+				},
 			},
 			},
 			want:       `[{"screen_name":"userA"},{"screen_name":"userB"}]`,
 			want:       `[{"screen_name":"userA"},{"screen_name":"userB"}]`,
 			statusCode: http.StatusOK,
 			statusCode: http.StatusOK,
@@ -142,6 +150,7 @@ func TestUserHandler_POST(t *testing.T) {
 	tt := []struct {
 	tt := []struct {
 		name           string
 		name           string
 		body           string
 		body           string
+		UUID           uuid.UUID
 		user           state.User
 		user           state.User
 		userHandlerErr error
 		userHandlerErr error
 		want           string
 		want           string
@@ -150,10 +159,12 @@ func TestUserHandler_POST(t *testing.T) {
 		{
 		{
 			name: "with valid user",
 			name: "with valid user",
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
+			UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
 			user: func() state.User {
 			user: func() state.User {
 				user := state.User{
 				user := state.User{
-					AuthKey:    "theAuthKey",
-					ScreenName: "userA",
+					AuthKey:           uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
 				}
 				}
 				assert.NoError(t, user.HashPassword("thepassword"))
 				assert.NoError(t, user.HashPassword("thepassword"))
 				return user
 				return user
@@ -171,10 +182,12 @@ func TestUserHandler_POST(t *testing.T) {
 		{
 		{
 			name: "user handler error",
 			name: "user handler error",
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
+			UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
 			user: func() state.User {
 			user: func() state.User {
 				user := state.User{
 				user := state.User{
-					AuthKey:    "theAuthKey",
-					ScreenName: "userA",
+					AuthKey:           uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
 				}
 				}
 				assert.NoError(t, user.HashPassword("thepassword"))
 				assert.NoError(t, user.HashPassword("thepassword"))
 				return user
 				return user
@@ -186,10 +199,12 @@ func TestUserHandler_POST(t *testing.T) {
 		{
 		{
 			name: "duplicate user",
 			name: "duplicate user",
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
+			UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
 			user: func() state.User {
 			user: func() state.User {
 				user := state.User{
 				user := state.User{
-					AuthKey:    "theAuthKey",
-					ScreenName: "userA",
+					AuthKey:           uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
 				}
 				}
 				assert.NoError(t, user.HashPassword("thepassword"))
 				assert.NoError(t, user.HashPassword("thepassword"))
 				return user
 				return user
@@ -206,16 +221,14 @@ func TestUserHandler_POST(t *testing.T) {
 			responseRecorder := httptest.NewRecorder()
 			responseRecorder := httptest.NewRecorder()
 
 
 			userManager := newMockUserManager(t)
 			userManager := newMockUserManager(t)
-			if tc.user.ScreenName != "" {
+			if tc.user.IdentScreenName.String() != "" {
 				userManager.EXPECT().
 				userManager.EXPECT().
 					InsertUser(tc.user).
 					InsertUser(tc.user).
 					Return(tc.userHandlerErr)
 					Return(tc.userHandlerErr)
 			}
 			}
 
 
-			newUser := func() state.User {
-				return tc.user
-			}
-			userHandler(responseRecorder, request, userManager, newUser, slog.Default())
+			newUUID := func() uuid.UUID { return tc.UUID }
+			userHandler(responseRecorder, request, userManager, newUUID, slog.Default())
 
 
 			if responseRecorder.Code != tc.statusCode {
 			if responseRecorder.Code != tc.statusCode {
 				t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
 				t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
@@ -241,7 +254,7 @@ func TestUserHandler_DELETE(t *testing.T) {
 			name: "with valid user",
 			name: "with valid user",
 			body: `{"screen_name":"userA"}`,
 			body: `{"screen_name":"userA"}`,
 			user: state.User{
 			user: state.User{
-				ScreenName: "userA",
+				IdentScreenName: state.NewIdentScreenName("userA"),
 			},
 			},
 			want:       `User account successfully deleted.`,
 			want:       `User account successfully deleted.`,
 			statusCode: http.StatusNoContent,
 			statusCode: http.StatusNoContent,
@@ -250,7 +263,7 @@ func TestUserHandler_DELETE(t *testing.T) {
 			name: "with non-existent user",
 			name: "with non-existent user",
 			body: `{"screen_name":"userA"}`,
 			body: `{"screen_name":"userA"}`,
 			user: state.User{
 			user: state.User{
-				ScreenName: "userA",
+				IdentScreenName: state.NewIdentScreenName("userA"),
 			},
 			},
 			userHandlerErr: state.ErrNoUser,
 			userHandlerErr: state.ErrNoUser,
 			want:           `user does not exist`,
 			want:           `user does not exist`,
@@ -267,7 +280,7 @@ func TestUserHandler_DELETE(t *testing.T) {
 			name: "user handler error",
 			name: "user handler error",
 			body: `{"screen_name":"userA"}`,
 			body: `{"screen_name":"userA"}`,
 			user: state.User{
 			user: state.User{
-				ScreenName: "userA",
+				IdentScreenName: state.NewIdentScreenName("userA"),
 			},
 			},
 			userHandlerErr: io.EOF,
 			userHandlerErr: io.EOF,
 			want:           `internal server error`,
 			want:           `internal server error`,
@@ -281,9 +294,9 @@ func TestUserHandler_DELETE(t *testing.T) {
 			responseRecorder := httptest.NewRecorder()
 			responseRecorder := httptest.NewRecorder()
 
 
 			userManager := newMockUserManager(t)
 			userManager := newMockUserManager(t)
-			if tc.user.ScreenName != "" {
+			if tc.user.IdentScreenName.String() != "" {
 				userManager.EXPECT().
 				userManager.EXPECT().
-					DeleteUser(tc.user.ScreenName).
+					DeleteUser(tc.user.IdentScreenName).
 					Return(tc.userHandlerErr)
 					Return(tc.userHandlerErr)
 			}
 			}
 
 
@@ -305,6 +318,7 @@ func TestUserPasswordHandler_PUT(t *testing.T) {
 		name           string
 		name           string
 		body           string
 		body           string
 		user           state.User
 		user           state.User
+		UUID           uuid.UUID
 		userHandlerErr error
 		userHandlerErr error
 		want           string
 		want           string
 		statusCode     int
 		statusCode     int
@@ -312,10 +326,12 @@ func TestUserPasswordHandler_PUT(t *testing.T) {
 		{
 		{
 			name: "with valid password",
 			name: "with valid password",
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
+			UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
 			user: func() state.User {
 			user: func() state.User {
 				user := state.User{
 				user := state.User{
-					AuthKey:    "theAuthKey",
-					ScreenName: "userA",
+					AuthKey:           uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
 				}
 				}
 				assert.NoError(t, user.HashPassword("thepassword"))
 				assert.NoError(t, user.HashPassword("thepassword"))
 				return user
 				return user
@@ -333,10 +349,12 @@ func TestUserPasswordHandler_PUT(t *testing.T) {
 		{
 		{
 			name: "user password handler error",
 			name: "user password handler error",
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
+			UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
 			user: func() state.User {
 			user: func() state.User {
 				user := state.User{
 				user := state.User{
-					AuthKey:    "theAuthKey",
-					ScreenName: "userA",
+					AuthKey:           uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
 				}
 				}
 				assert.NoError(t, user.HashPassword("thepassword"))
 				assert.NoError(t, user.HashPassword("thepassword"))
 				return user
 				return user
@@ -348,10 +366,12 @@ func TestUserPasswordHandler_PUT(t *testing.T) {
 		{
 		{
 			name: "user doesn't exist",
 			name: "user doesn't exist",
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
 			body: `{"screen_name":"userA", "password":"thepassword"}`,
+			UUID: uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b"),
 			user: func() state.User {
 			user: func() state.User {
 				user := state.User{
 				user := state.User{
-					AuthKey:    "theAuthKey",
-					ScreenName: "userA",
+					AuthKey:           uuid.MustParse("07c70701-ba68-49a9-9f9b-67a53816e37b").String(),
+					DisplayScreenName: "userA",
+					IdentScreenName:   state.NewIdentScreenName("userA"),
 				}
 				}
 				assert.NoError(t, user.HashPassword("thepassword"))
 				assert.NoError(t, user.HashPassword("thepassword"))
 				return user
 				return user
@@ -368,16 +388,14 @@ func TestUserPasswordHandler_PUT(t *testing.T) {
 			responseRecorder := httptest.NewRecorder()
 			responseRecorder := httptest.NewRecorder()
 
 
 			userManager := newMockUserManager(t)
 			userManager := newMockUserManager(t)
-			if tc.user.ScreenName != "" {
+			if tc.user.IdentScreenName.String() != "" {
 				userManager.EXPECT().
 				userManager.EXPECT().
 					SetUserPassword(tc.user).
 					SetUserPassword(tc.user).
 					Return(tc.userHandlerErr)
 					Return(tc.userHandlerErr)
 			}
 			}
 
 
-			uf := func() state.User {
-				return tc.user
-			}
-			userPasswordHandler(responseRecorder, request, userManager, uf, slog.Default())
+			newUUID := func() uuid.UUID { return tc.UUID }
+			userPasswordHandler(responseRecorder, request, userManager, newUUID, slog.Default())
 
 
 			if responseRecorder.Code != tc.statusCode {
 			if responseRecorder.Code != tc.statusCode {
 				t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
 				t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)

+ 14 - 14
server/http/mock_user_manager_test.go

@@ -78,7 +78,7 @@ func (_c *mockUserManager_AllUsers_Call) RunAndReturn(run func() ([]state.User,
 }
 }
 
 
 // DeleteUser provides a mock function with given fields: screenName
 // DeleteUser provides a mock function with given fields: screenName
-func (_m *mockUserManager) DeleteUser(screenName string) error {
+func (_m *mockUserManager) DeleteUser(screenName state.IdentScreenName) error {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -86,7 +86,7 @@ func (_m *mockUserManager) DeleteUser(screenName string) error {
 	}
 	}
 
 
 	var r0 error
 	var r0 error
-	if rf, ok := ret.Get(0).(func(string) error); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) error); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		r0 = ret.Error(0)
 		r0 = ret.Error(0)
@@ -101,14 +101,14 @@ type mockUserManager_DeleteUser_Call struct {
 }
 }
 
 
 // DeleteUser is a helper method to define mock.On call
 // DeleteUser is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockUserManager_Expecter) DeleteUser(screenName interface{}) *mockUserManager_DeleteUser_Call {
 func (_e *mockUserManager_Expecter) DeleteUser(screenName interface{}) *mockUserManager_DeleteUser_Call {
 	return &mockUserManager_DeleteUser_Call{Call: _e.mock.On("DeleteUser", screenName)}
 	return &mockUserManager_DeleteUser_Call{Call: _e.mock.On("DeleteUser", screenName)}
 }
 }
 
 
-func (_c *mockUserManager_DeleteUser_Call) Run(run func(screenName string)) *mockUserManager_DeleteUser_Call {
+func (_c *mockUserManager_DeleteUser_Call) Run(run func(screenName state.IdentScreenName)) *mockUserManager_DeleteUser_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -118,7 +118,7 @@ func (_c *mockUserManager_DeleteUser_Call) Return(_a0 error) *mockUserManager_De
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockUserManager_DeleteUser_Call) RunAndReturn(run func(string) error) *mockUserManager_DeleteUser_Call {
+func (_c *mockUserManager_DeleteUser_Call) RunAndReturn(run func(state.IdentScreenName) error) *mockUserManager_DeleteUser_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
@@ -216,7 +216,7 @@ func (_c *mockUserManager_SetUserPassword_Call) RunAndReturn(run func(state.User
 }
 }
 
 
 // User provides a mock function with given fields: screenName
 // User provides a mock function with given fields: screenName
-func (_m *mockUserManager) User(screenName string) (*state.User, error) {
+func (_m *mockUserManager) User(screenName state.IdentScreenName) (*state.User, error) {
 	ret := _m.Called(screenName)
 	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -225,10 +225,10 @@ func (_m *mockUserManager) User(screenName string) (*state.User, error) {
 
 
 	var r0 *state.User
 	var r0 *state.User
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (*state.User, error)); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
 		return rf(screenName)
 		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) *state.User); ok {
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
 		r0 = rf(screenName)
 		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
@@ -236,7 +236,7 @@ func (_m *mockUserManager) User(screenName string) (*state.User, error) {
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
 		r1 = rf(screenName)
 		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -251,14 +251,14 @@ type mockUserManager_User_Call struct {
 }
 }
 
 
 // User is a helper method to define mock.On call
 // User is a helper method to define mock.On call
-//   - screenName string
+//   - screenName state.IdentScreenName
 func (_e *mockUserManager_Expecter) User(screenName interface{}) *mockUserManager_User_Call {
 func (_e *mockUserManager_Expecter) User(screenName interface{}) *mockUserManager_User_Call {
 	return &mockUserManager_User_Call{Call: _e.mock.On("User", screenName)}
 	return &mockUserManager_User_Call{Call: _e.mock.On("User", screenName)}
 }
 }
 
 
-func (_c *mockUserManager_User_Call) Run(run func(screenName string)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) Run(run func(screenName state.IdentScreenName)) *mockUserManager_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -268,7 +268,7 @@ func (_c *mockUserManager_User_Call) Return(_a0 *state.User, _a1 error) *mockUse
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockUserManager_User_Call) RunAndReturn(run func(string) (*state.User, error)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockUserManager_User_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 3 - 3
server/oscar/auth.go

@@ -16,9 +16,9 @@ import (
 
 
 type AuthService interface {
 type AuthService interface {
 	BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error)
 	BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error)
-	BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, fn func(screenName string) (state.User, error)) (wire.SNACMessage, error)
-	FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName string) (state.User, error)) (wire.TLVRestBlock, error)
-	RegisterBOSSession(sessionID string) (*state.Session, error)
+	BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)
+	FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)
+	RegisterBOSSession(screenName state.IdentScreenName) (*state.Session, error)
 	RegisterChatSession(loginCookie []byte) (*state.Session, error)
 	RegisterChatSession(loginCookie []byte) (*state.Session, error)
 	Signout(ctx context.Context, sess *state.Session) error
 	Signout(ctx context.Context, sess *state.Session) error
 	SignoutChat(ctx context.Context, sess *state.Session) error
 	SignoutChat(ctx context.Context, sess *state.Session) error

+ 4 - 3
server/oscar/bos.go

@@ -9,6 +9,7 @@ import (
 	"os"
 	"os"
 
 
 	"github.com/mk6i/retro-aim-server/config"
 	"github.com/mk6i/retro-aim-server/config"
+	"github.com/mk6i/retro-aim-server/state"
 	"github.com/mk6i/retro-aim-server/wire"
 	"github.com/mk6i/retro-aim-server/wire"
 )
 )
 
 
@@ -77,12 +78,12 @@ func (rt BOSServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteClo
 		return errors.New("unable to get session id from payload")
 		return errors.New("unable to get session id from payload")
 	}
 	}
 
 
-	token, err := rt.CookieCracker.Crack(authCookie)
+	screenName, err := rt.CookieCracker.Crack(authCookie)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	sess, err := rt.RegisterBOSSession(string(token))
+	sess, err := rt.RegisterBOSSession(state.NewIdentScreenName(string(screenName)))
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -98,7 +99,7 @@ func (rt BOSServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteClo
 		}
 		}
 	}()
 	}()
 
 
-	ctx = context.WithValue(ctx, "screenName", sess.ScreenName())
+	ctx = context.WithValue(ctx, "screenName", sess.IdentScreenName())
 
 
 	msg := rt.OnlineNotifier.HostOnline()
 	msg := rt.OnlineNotifier.HostOnline()
 	if err := flapc.SendSNAC(msg.Frame, msg.Body); err != nil {
 	if err := flapc.SendSNAC(msg.Frame, msg.Body); err != nil {

+ 1 - 1
server/oscar/bos_test.go

@@ -81,7 +81,7 @@ func TestBOSService_handleNewConnection(t *testing.T) {
 
 
 	authService := newMockAuthService(t)
 	authService := newMockAuthService(t)
 	authService.EXPECT().
 	authService.EXPECT().
-		RegisterBOSSession("user_screen_name").
+		RegisterBOSSession(state.NewIdentScreenName("user_screen_name")).
 		Return(sess, nil)
 		Return(sess, nil)
 	authService.EXPECT().
 	authService.EXPECT().
 		Signout(mock.Anything, sess).
 		Signout(mock.Anything, sess).

+ 1 - 1
server/oscar/chat.go

@@ -95,6 +95,6 @@ func (rt ChatServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteCl
 		return err
 		return err
 	}
 	}
 
 
-	ctx = context.WithValue(ctx, "screenName", chatSess.ScreenName())
+	ctx = context.WithValue(ctx, "screenName", chatSess.IdentScreenName())
 	return dispatchIncomingMessages(ctx, chatSess, flapc, rwc, rt.Logger, rt.Handler, rt.Config)
 	return dispatchIncomingMessages(ctx, chatSess, flapc, rwc, rt.Logger, rt.Handler, rt.Config)
 }
 }

+ 1 - 1
server/oscar/connection_test.go

@@ -60,7 +60,7 @@ func TestHandleChatConnection_MessageRelay(t *testing.T) {
 
 
 	// relay messages to user session
 	// relay messages to user session
 	for _, msg := range inboundMsgs {
 	for _, msg := range inboundMsgs {
-		sessionManager.RelayToScreenName(context.Background(), "bob", msg)
+		sessionManager.RelayToScreenName(context.Background(), state.NewIdentScreenName("bob"), msg)
 	}
 	}
 
 
 	// consume and verify the relayed messages
 	// consume and verify the relayed messages

+ 1 - 1
server/oscar/middleware/logger.go

@@ -59,7 +59,7 @@ type handler struct {
 
 
 func (h handler) Handle(ctx context.Context, r slog.Record) error {
 func (h handler) Handle(ctx context.Context, r slog.Record) error {
 	if sn := ctx.Value("screenName"); sn != nil {
 	if sn := ctx.Value("screenName"); sn != nil {
-		r.AddAttrs(slog.Attr{Key: "screenName", Value: slog.StringValue(sn.(string))})
+		//r.AddAttrs(slog.Attr{Key: "screenName", Value: slog.StringValue(sn.(string))})
 	}
 	}
 	if ip := ctx.Value("ip"); ip != nil {
 	if ip := ctx.Value("ip"); ip != nil {
 		r.AddAttrs(slog.Attr{Key: "ip", Value: slog.StringValue(ip.(string))})
 		r.AddAttrs(slog.Attr{Key: "ip", Value: slog.StringValue(ip.(string))})

+ 38 - 38
server/oscar/mock_auth_test.go

@@ -83,9 +83,9 @@ func (_c *mockAuthService_BUCPChallenge_Call) RunAndReturn(run func(wire.SNAC_0x
 	return _c
 	return _c
 }
 }
 
 
-// BUCPLogin provides a mock function with given fields: bodyIn, fn
-func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, fn func(string) (state.User, error)) (wire.SNACMessage, error) {
-	ret := _m.Called(bodyIn, fn)
+// BUCPLogin provides a mock function with given fields: bodyIn, newUserFn
+func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
+	ret := _m.Called(bodyIn, newUserFn)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for BUCPLogin")
 		panic("no return value specified for BUCPLogin")
@@ -93,17 +93,17 @@ func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
 
 
 	var r0 wire.SNACMessage
 	var r0 wire.SNACMessage
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(string) (state.User, error)) (wire.SNACMessage, error)); ok {
-		return rf(bodyIn, fn)
+	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)); ok {
+		return rf(bodyIn, newUserFn)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(string) (state.User, error)) wire.SNACMessage); ok {
-		r0 = rf(bodyIn, fn)
+	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) wire.SNACMessage); ok {
+		r0 = rf(bodyIn, newUserFn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(wire.SNACMessage)
 		r0 = ret.Get(0).(wire.SNACMessage)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(string) (state.User, error)) error); ok {
-		r1 = rf(bodyIn, fn)
+	if rf, ok := ret.Get(1).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) error); ok {
+		r1 = rf(bodyIn, newUserFn)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -118,14 +118,14 @@ type mockAuthService_BUCPLogin_Call struct {
 
 
 // BUCPLogin is a helper method to define mock.On call
 // BUCPLogin is a helper method to define mock.On call
 //   - bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
 //   - bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
-//   - fn func(string)(state.User , error)
-func (_e *mockAuthService_Expecter) BUCPLogin(bodyIn interface{}, fn interface{}) *mockAuthService_BUCPLogin_Call {
-	return &mockAuthService_BUCPLogin_Call{Call: _e.mock.On("BUCPLogin", bodyIn, fn)}
+//   - newUserFn func(state.DisplayScreenName)(state.User , error)
+func (_e *mockAuthService_Expecter) BUCPLogin(bodyIn interface{}, newUserFn interface{}) *mockAuthService_BUCPLogin_Call {
+	return &mockAuthService_BUCPLogin_Call{Call: _e.mock.On("BUCPLogin", bodyIn, newUserFn)}
 }
 }
 
 
-func (_c *mockAuthService_BUCPLogin_Call) Run(run func(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, fn func(string) (state.User, error))) *mockAuthService_BUCPLogin_Call {
+func (_c *mockAuthService_BUCPLogin_Call) Run(run func(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_BUCPLogin_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.SNAC_0x17_0x02_BUCPLoginRequest), args[1].(func(string) (state.User, error)))
+		run(args[0].(wire.SNAC_0x17_0x02_BUCPLoginRequest), args[1].(func(state.DisplayScreenName) (state.User, error)))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -135,13 +135,13 @@ func (_c *mockAuthService_BUCPLogin_Call) Return(_a0 wire.SNACMessage, _a1 error
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockAuthService_BUCPLogin_Call) RunAndReturn(run func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(string) (state.User, error)) (wire.SNACMessage, error)) *mockAuthService_BUCPLogin_Call {
+func (_c *mockAuthService_BUCPLogin_Call) RunAndReturn(run func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)) *mockAuthService_BUCPLogin_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
 // FLAPLogin provides a mock function with given fields: frame, newUserFn
 // FLAPLogin provides a mock function with given fields: frame, newUserFn
-func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(string) (state.User, error)) (wire.TLVRestBlock, error) {
+func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
 	ret := _m.Called(frame, newUserFn)
 	ret := _m.Called(frame, newUserFn)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
@@ -150,16 +150,16 @@ func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(
 
 
 	var r0 wire.TLVRestBlock
 	var r0 wire.TLVRestBlock
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(string) (state.User, error)) (wire.TLVRestBlock, error)); ok {
+	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)); ok {
 		return rf(frame, newUserFn)
 		return rf(frame, newUserFn)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(string) (state.User, error)) wire.TLVRestBlock); ok {
+	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) wire.TLVRestBlock); ok {
 		r0 = rf(frame, newUserFn)
 		r0 = rf(frame, newUserFn)
 	} else {
 	} else {
 		r0 = ret.Get(0).(wire.TLVRestBlock)
 		r0 = ret.Get(0).(wire.TLVRestBlock)
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(wire.FLAPSignonFrame, func(string) (state.User, error)) error); ok {
+	if rf, ok := ret.Get(1).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) error); ok {
 		r1 = rf(frame, newUserFn)
 		r1 = rf(frame, newUserFn)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
@@ -175,14 +175,14 @@ type mockAuthService_FLAPLogin_Call struct {
 
 
 // FLAPLogin is a helper method to define mock.On call
 // FLAPLogin is a helper method to define mock.On call
 //   - frame wire.FLAPSignonFrame
 //   - frame wire.FLAPSignonFrame
-//   - newUserFn func(string)(state.User , error)
+//   - newUserFn func(state.DisplayScreenName)(state.User , error)
 func (_e *mockAuthService_Expecter) FLAPLogin(frame interface{}, newUserFn interface{}) *mockAuthService_FLAPLogin_Call {
 func (_e *mockAuthService_Expecter) FLAPLogin(frame interface{}, newUserFn interface{}) *mockAuthService_FLAPLogin_Call {
 	return &mockAuthService_FLAPLogin_Call{Call: _e.mock.On("FLAPLogin", frame, newUserFn)}
 	return &mockAuthService_FLAPLogin_Call{Call: _e.mock.On("FLAPLogin", frame, newUserFn)}
 }
 }
 
 
-func (_c *mockAuthService_FLAPLogin_Call) Run(run func(frame wire.FLAPSignonFrame, newUserFn func(string) (state.User, error))) *mockAuthService_FLAPLogin_Call {
+func (_c *mockAuthService_FLAPLogin_Call) Run(run func(frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_FLAPLogin_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.FLAPSignonFrame), args[1].(func(string) (state.User, error)))
+		run(args[0].(wire.FLAPSignonFrame), args[1].(func(state.DisplayScreenName) (state.User, error)))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -192,14 +192,14 @@ func (_c *mockAuthService_FLAPLogin_Call) Return(_a0 wire.TLVRestBlock, _a1 erro
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockAuthService_FLAPLogin_Call) RunAndReturn(run func(wire.FLAPSignonFrame, func(string) (state.User, error)) (wire.TLVRestBlock, error)) *mockAuthService_FLAPLogin_Call {
+func (_c *mockAuthService_FLAPLogin_Call) RunAndReturn(run func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)) *mockAuthService_FLAPLogin_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }
 
 
-// RegisterBOSSession provides a mock function with given fields: sessionID
-func (_m *mockAuthService) RegisterBOSSession(sessionID string) (*state.Session, error) {
-	ret := _m.Called(sessionID)
+// RegisterBOSSession provides a mock function with given fields: screenName
+func (_m *mockAuthService) RegisterBOSSession(screenName state.IdentScreenName) (*state.Session, error) {
+	ret := _m.Called(screenName)
 
 
 	if len(ret) == 0 {
 	if len(ret) == 0 {
 		panic("no return value specified for RegisterBOSSession")
 		panic("no return value specified for RegisterBOSSession")
@@ -207,19 +207,19 @@ func (_m *mockAuthService) RegisterBOSSession(sessionID string) (*state.Session,
 
 
 	var r0 *state.Session
 	var r0 *state.Session
 	var r1 error
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (*state.Session, error)); ok {
-		return rf(sessionID)
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.Session, error)); ok {
+		return rf(screenName)
 	}
 	}
-	if rf, ok := ret.Get(0).(func(string) *state.Session); ok {
-		r0 = rf(sessionID)
+	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.Session); ok {
+		r0 = rf(screenName)
 	} else {
 	} else {
 		if ret.Get(0) != nil {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.Session)
 			r0 = ret.Get(0).(*state.Session)
 		}
 		}
 	}
 	}
 
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(sessionID)
+	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
+		r1 = rf(screenName)
 	} else {
 	} else {
 		r1 = ret.Error(1)
 		r1 = ret.Error(1)
 	}
 	}
@@ -233,14 +233,14 @@ type mockAuthService_RegisterBOSSession_Call struct {
 }
 }
 
 
 // RegisterBOSSession is a helper method to define mock.On call
 // RegisterBOSSession is a helper method to define mock.On call
-//   - sessionID string
-func (_e *mockAuthService_Expecter) RegisterBOSSession(sessionID interface{}) *mockAuthService_RegisterBOSSession_Call {
-	return &mockAuthService_RegisterBOSSession_Call{Call: _e.mock.On("RegisterBOSSession", sessionID)}
+//   - screenName state.IdentScreenName
+func (_e *mockAuthService_Expecter) RegisterBOSSession(screenName interface{}) *mockAuthService_RegisterBOSSession_Call {
+	return &mockAuthService_RegisterBOSSession_Call{Call: _e.mock.On("RegisterBOSSession", screenName)}
 }
 }
 
 
-func (_c *mockAuthService_RegisterBOSSession_Call) Run(run func(sessionID string)) *mockAuthService_RegisterBOSSession_Call {
+func (_c *mockAuthService_RegisterBOSSession_Call) Run(run func(screenName state.IdentScreenName)) *mockAuthService_RegisterBOSSession_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(state.IdentScreenName))
 	})
 	})
 	return _c
 	return _c
 }
 }
@@ -250,7 +250,7 @@ func (_c *mockAuthService_RegisterBOSSession_Call) Return(_a0 *state.Session, _a
 	return _c
 	return _c
 }
 }
 
 
-func (_c *mockAuthService_RegisterBOSSession_Call) RunAndReturn(run func(string) (*state.Session, error)) *mockAuthService_RegisterBOSSession_Call {
+func (_c *mockAuthService_RegisterBOSSession_Call) RunAndReturn(run func(state.IdentScreenName) (*state.Session, error)) *mockAuthService_RegisterBOSSession_Call {
 	_c.Call.Return(run)
 	_c.Call.Return(run)
 	return _c
 	return _c
 }
 }

+ 10 - 10
state/buddy_list_store.go

@@ -4,34 +4,34 @@ import "sync"
 
 
 // AdjListBuddyListStore implements a buddy list using an adjacency list.
 // AdjListBuddyListStore implements a buddy list using an adjacency list.
 type AdjListBuddyListStore struct {
 type AdjListBuddyListStore struct {
-	buddies map[string]map[string]bool
+	buddies map[IdentScreenName]map[IdentScreenName]bool
 	mu      sync.RWMutex // ensures thread-safe access
 	mu      sync.RWMutex // ensures thread-safe access
 }
 }
 
 
 // NewAdjListBuddyListStore initializes a new instance of AdjListBuddyListStore.
 // NewAdjListBuddyListStore initializes a new instance of AdjListBuddyListStore.
 func NewAdjListBuddyListStore() *AdjListBuddyListStore {
 func NewAdjListBuddyListStore() *AdjListBuddyListStore {
 	return &AdjListBuddyListStore{
 	return &AdjListBuddyListStore{
-		buddies: make(map[string]map[string]bool),
+		buddies: make(map[IdentScreenName]map[IdentScreenName]bool),
 	}
 	}
 }
 }
 
 
 // AddBuddy adds buddyScreenName to userScreenName's buddy list.
 // AddBuddy adds buddyScreenName to userScreenName's buddy list.
-func (store *AdjListBuddyListStore) AddBuddy(userScreenName, buddyScreenName string) {
+func (store *AdjListBuddyListStore) AddBuddy(userScreenName, buddyScreenName IdentScreenName) {
 	store.mu.Lock()
 	store.mu.Lock()
 	defer store.mu.Unlock()
 	defer store.mu.Unlock()
 
 
 	if _, exists := store.buddies[userScreenName]; !exists {
 	if _, exists := store.buddies[userScreenName]; !exists {
-		store.buddies[userScreenName] = make(map[string]bool)
+		store.buddies[userScreenName] = make(map[IdentScreenName]bool)
 	}
 	}
 	store.buddies[userScreenName][buddyScreenName] = true
 	store.buddies[userScreenName][buddyScreenName] = true
 }
 }
 
 
 // WhoAddedUser returns a list of screen names who have userScreenName in their buddy lists.
 // WhoAddedUser returns a list of screen names who have userScreenName in their buddy lists.
-func (store *AdjListBuddyListStore) WhoAddedUser(userScreenName string) []string {
+func (store *AdjListBuddyListStore) WhoAddedUser(userScreenName IdentScreenName) []IdentScreenName {
 	store.mu.RLock()
 	store.mu.RLock()
 	defer store.mu.RUnlock()
 	defer store.mu.RUnlock()
 
 
-	var users []string
+	var users []IdentScreenName
 	for user, buddies := range store.buddies {
 	for user, buddies := range store.buddies {
 		if buddies[userScreenName] {
 		if buddies[userScreenName] {
 			users = append(users, user)
 			users = append(users, user)
@@ -41,12 +41,12 @@ func (store *AdjListBuddyListStore) WhoAddedUser(userScreenName string) []string
 }
 }
 
 
 // Buddies returns a list of all buddies associated with the specified userScreenName.
 // Buddies returns a list of all buddies associated with the specified userScreenName.
-func (store *AdjListBuddyListStore) Buddies(userScreenName string) []string {
+func (store *AdjListBuddyListStore) Buddies(userScreenName IdentScreenName) []IdentScreenName {
 	store.mu.RLock()
 	store.mu.RLock()
 	defer store.mu.RUnlock()
 	defer store.mu.RUnlock()
 
 
 	if buddies, exists := store.buddies[userScreenName]; exists {
 	if buddies, exists := store.buddies[userScreenName]; exists {
-		users := make([]string, 0, len(buddies))
+		users := make([]IdentScreenName, 0, len(buddies))
 		for buddy := range buddies {
 		for buddy := range buddies {
 			users = append(users, buddy)
 			users = append(users, buddy)
 		}
 		}
@@ -56,7 +56,7 @@ func (store *AdjListBuddyListStore) Buddies(userScreenName string) []string {
 }
 }
 
 
 // DeleteBuddy removes buddyScreenName from userScreenName's buddy list.
 // DeleteBuddy removes buddyScreenName from userScreenName's buddy list.
-func (store *AdjListBuddyListStore) DeleteBuddy(userScreenName, buddyScreenName string) {
+func (store *AdjListBuddyListStore) DeleteBuddy(userScreenName, buddyScreenName IdentScreenName) {
 	store.mu.Lock()
 	store.mu.Lock()
 	defer store.mu.Unlock()
 	defer store.mu.Unlock()
 
 
@@ -69,7 +69,7 @@ func (store *AdjListBuddyListStore) DeleteBuddy(userScreenName, buddyScreenName
 }
 }
 
 
 // DeleteUser removes userScreenName's buddy list.
 // DeleteUser removes userScreenName's buddy list.
-func (store *AdjListBuddyListStore) DeleteUser(userScreenName string) {
+func (store *AdjListBuddyListStore) DeleteUser(userScreenName IdentScreenName) {
 	store.mu.Lock()
 	store.mu.Lock()
 	defer store.mu.Unlock()
 	defer store.mu.Unlock()
 
 

+ 49 - 38
state/buddy_list_store_test.go

@@ -8,68 +8,79 @@ import (
 
 
 func TestAdjListBuddyListStore_AddBuddy_Buddies(t *testing.T) {
 func TestAdjListBuddyListStore_AddBuddy_Buddies(t *testing.T) {
 	store := NewAdjListBuddyListStore()
 	store := NewAdjListBuddyListStore()
-	store.AddBuddy("alice", "bob")
-	store.AddBuddy("bob", "alice")
-	store.AddBuddy("alice", "charlie")
-	store.AddBuddy("alice", "dave")
-	store.AddBuddy("dave", "bob")
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("bob"), NewIdentScreenName("alice"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("charlie"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("dave"))
+	store.AddBuddy(NewIdentScreenName("dave"), NewIdentScreenName("bob"))
 
 
-	buddies := store.Buddies("alice")
-	assert.ElementsMatch(t, []string{"bob", "charlie", "dave"}, buddies)
+	buddies := store.Buddies(NewIdentScreenName("alice"))
+	assert.ElementsMatch(t, []IdentScreenName{
+		NewIdentScreenName("bob"),
+		NewIdentScreenName("charlie"),
+		NewIdentScreenName("dave"),
+	}, buddies)
 }
 }
 
 
 func TestAdjListBuddyListStore_DeleteBuddy_OneBuddy(t *testing.T) {
 func TestAdjListBuddyListStore_DeleteBuddy_OneBuddy(t *testing.T) {
 	store := NewAdjListBuddyListStore()
 	store := NewAdjListBuddyListStore()
-	store.AddBuddy("alice", "bob")
-	store.AddBuddy("bob", "alice")
-	store.AddBuddy("alice", "charlie")
-	store.AddBuddy("alice", "dave")
-	store.AddBuddy("dave", "bob")
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("bob"), NewIdentScreenName("alice"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("charlie"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("dave"))
+	store.AddBuddy(NewIdentScreenName("dave"), NewIdentScreenName("bob"))
 
 
-	store.DeleteBuddy("alice", "bob")
+	store.DeleteBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
 
 
-	buddies := store.Buddies("alice")
-	assert.ElementsMatch(t, []string{"charlie", "dave"}, buddies)
+	buddies := store.Buddies(NewIdentScreenName("alice"))
+	assert.ElementsMatch(t, []IdentScreenName{
+		NewIdentScreenName("charlie"),
+		NewIdentScreenName("dave"),
+	}, buddies)
 }
 }
 
 
 func TestAdjListBuddyListStore_DeleteBuddy_AllBuddies(t *testing.T) {
 func TestAdjListBuddyListStore_DeleteBuddy_AllBuddies(t *testing.T) {
 	store := NewAdjListBuddyListStore()
 	store := NewAdjListBuddyListStore()
-	store.AddBuddy("alice", "bob")
-	store.AddBuddy("bob", "alice")
-	store.AddBuddy("alice", "charlie")
-	store.AddBuddy("alice", "dave")
-	store.AddBuddy("dave", "bob")
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("bob"), NewIdentScreenName("alice"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("charlie"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("dave"))
+	store.AddBuddy(NewIdentScreenName("dave"), NewIdentScreenName("bob"))
 
 
-	store.DeleteBuddy("alice", "bob")
-	store.DeleteBuddy("alice", "charlie")
-	store.DeleteBuddy("alice", "dave")
+	store.DeleteBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
+	store.DeleteBuddy(NewIdentScreenName("alice"), NewIdentScreenName("charlie"))
+	store.DeleteBuddy(NewIdentScreenName("alice"), NewIdentScreenName("dave"))
 
 
-	buddies := store.Buddies("alice")
+	buddies := store.Buddies(NewIdentScreenName("alice"))
 	assert.Nil(t, buddies)
 	assert.Nil(t, buddies)
 }
 }
 
 
 func TestAdjListBuddyListStore_DeleteUser(t *testing.T) {
 func TestAdjListBuddyListStore_DeleteUser(t *testing.T) {
 	store := NewAdjListBuddyListStore()
 	store := NewAdjListBuddyListStore()
-	store.AddBuddy("alice", "bob")
-	store.AddBuddy("bob", "alice")
-	store.AddBuddy("alice", "charlie")
-	store.AddBuddy("alice", "dave")
-	store.AddBuddy("dave", "bob")
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("bob"), NewIdentScreenName("alice"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("charlie"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("dave"))
+	store.AddBuddy(NewIdentScreenName("dave"), NewIdentScreenName("bob"))
 
 
-	store.DeleteUser("alice")
+	store.DeleteUser(NewIdentScreenName("alice"))
 
 
-	buddies := store.Buddies("alice")
+	buddies := store.Buddies(NewIdentScreenName("alice"))
 	assert.Nil(t, buddies)
 	assert.Nil(t, buddies)
 }
 }
 
 
 func TestAdjListBuddyListStore_WhoAddedUser(t *testing.T) {
 func TestAdjListBuddyListStore_WhoAddedUser(t *testing.T) {
 	store := NewAdjListBuddyListStore()
 	store := NewAdjListBuddyListStore()
-	store.AddBuddy("alice", "bob")
-	store.AddBuddy("alice", "charlie")
-	store.AddBuddy("charlie", "bob")
-	store.AddBuddy("dave", "bob")
-	store.AddBuddy("dave", "alive")
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("alice"), NewIdentScreenName("charlie"))
+	store.AddBuddy(NewIdentScreenName("charlie"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("dave"), NewIdentScreenName("bob"))
+	store.AddBuddy(NewIdentScreenName("dave"), NewIdentScreenName("alive"))
 
 
-	whoAddedBob := store.WhoAddedUser("bob")
-	assert.ElementsMatch(t, []string{"alice", "charlie", "dave"}, whoAddedBob)
+	whoAddedBob := store.WhoAddedUser(NewIdentScreenName("bob"))
+	assert.ElementsMatch(t, []IdentScreenName{
+		NewIdentScreenName("alice"),
+		NewIdentScreenName("charlie"),
+		NewIdentScreenName("dave"),
+	}, whoAddedBob)
 }
 }

+ 16 - 0
state/migrations/0003_formatted_screen_name.down.sql

@@ -0,0 +1,16 @@
+CREATE TABLE user
+(
+    screenName    VARCHAR(16) PRIMARY KEY,
+    authKey       TEXT,
+    strongMD5Pass TEXT,
+    weakMD5Pass   TEXT
+);
+
+INSERT INTO user
+SELECT displayScreenName,
+       authKey,
+       strongMD5Pass,
+       weakMD5Pass
+FROM users;
+
+DROP TABLE users;

+ 27 - 0
state/migrations/0003_formatted_screen_name.up.sql

@@ -0,0 +1,27 @@
+-- call the new table "users" since it's not a reserved word that we'll need to
+-- deal with for postgres in the future.
+CREATE TABLE users
+(
+    identScreenName   VARCHAR(16) PRIMARY KEY,
+    displayScreenName TEXT,
+    authKey           TEXT,
+    strongMD5Pass     TEXT,
+    weakMD5Pass       TEXT
+);
+
+INSERT INTO users
+SELECT LOWER(REPLACE(screenName, ' ', '')),
+       screenName,
+       authKey,
+       strongMD5Pass,
+       weakMD5Pass
+FROM user;
+
+DROP TABLE user;
+
+UPDATE feedbag
+SET name = LOWER(REPLACE(name, ' ', ''))
+WHERE classID IN (0, 2, 3);
+
+UPDATE feedbag
+SET screenName = LOWER(REPLACE(screenName, ' ', ''));

+ 37 - 22
state/session.go

@@ -23,21 +23,22 @@ const (
 // Session represents a user's current session. Unless stated otherwise, all
 // Session represents a user's current session. Unless stated otherwise, all
 // methods may be safely accessed by multiple goroutines.
 // methods may be safely accessed by multiple goroutines.
 type Session struct {
 type Session struct {
-	awayMessage    string
-	chatRoomCookie string
-	closed         bool
-	idle           bool
-	idleTime       time.Time
-	invisible      bool
-	msgCh          chan wire.SNACMessage
-	mutex          sync.RWMutex
-	nowFn          func() time.Time
-	signonComplete bool
-	screenName     string
-	signonTime     time.Time
-	stopCh         chan struct{}
-	warning        uint16
-	caps           [][16]byte
+	awayMessage       string
+	caps              [][16]byte
+	chatRoomCookie    string
+	closed            bool
+	displayScreenName DisplayScreenName
+	identScreenName   IdentScreenName
+	idle              bool
+	idleTime          time.Time
+	invisible         bool
+	msgCh             chan wire.SNACMessage
+	mutex             sync.RWMutex
+	nowFn             func() time.Time
+	signonComplete    bool
+	signonTime        time.Time
+	stopCh            chan struct{}
+	warning           uint16
 }
 }
 
 
 // NewSession returns a new instance of Session. By default, the user may have
 // NewSession returns a new instance of Session. By default, the user may have
@@ -74,18 +75,32 @@ func (s *Session) Invisible() bool {
 	return s.invisible
 	return s.invisible
 }
 }
 
 
-// SetScreenName sets the user's screen name.
-func (s *Session) SetScreenName(screenName string) {
+// SetIdentScreenName sets the user's screen name.
+func (s *Session) SetIdentScreenName(screenName IdentScreenName) {
 	s.mutex.Lock()
 	s.mutex.Lock()
 	defer s.mutex.Unlock()
 	defer s.mutex.Unlock()
-	s.screenName = screenName
+	s.identScreenName = screenName
 }
 }
 
 
-// ScreenName returns the user's screen name.
-func (s *Session) ScreenName() string {
+// IdentScreenName returns the user's screen name.
+func (s *Session) IdentScreenName() IdentScreenName {
 	s.mutex.RLock()
 	s.mutex.RLock()
 	defer s.mutex.RUnlock()
 	defer s.mutex.RUnlock()
-	return s.screenName
+	return s.identScreenName
+}
+
+// SetDisplayScreenName sets the user's screen name.
+func (s *Session) SetDisplayScreenName(displayScreenName DisplayScreenName) {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+	s.displayScreenName = displayScreenName
+}
+
+// DisplayScreenName returns the user's screen name.
+func (s *Session) DisplayScreenName() DisplayScreenName {
+	s.mutex.RLock()
+	defer s.mutex.RUnlock()
+	return s.displayScreenName
 }
 }
 
 
 // SetSignonTime sets the user's sign-ontime.
 // SetSignonTime sets the user's sign-ontime.
@@ -159,7 +174,7 @@ func (s *Session) TLVUserInfo() wire.TLVUserInfo {
 	s.mutex.RLock()
 	s.mutex.RLock()
 	defer s.mutex.RUnlock()
 	defer s.mutex.RUnlock()
 	return wire.TLVUserInfo{
 	return wire.TLVUserInfo{
-		ScreenName:   s.screenName,
+		ScreenName:   string(s.displayScreenName),
 		WarningLevel: s.warning,
 		WarningLevel: s.warning,
 		TLVBlock: wire.TLVBlock{
 		TLVBlock: wire.TLVBlock{
 			TLVList: s.userInfo(),
 			TLVList: s.userInfo(),

+ 20 - 18
state/session_manager.go

@@ -12,7 +12,7 @@ import (
 // synchronized message relay between sessions in the session pool. An
 // synchronized message relay between sessions in the session pool. An
 // InMemorySessionManager is safe for concurrent use by multiple goroutines.
 // InMemorySessionManager is safe for concurrent use by multiple goroutines.
 type InMemorySessionManager struct {
 type InMemorySessionManager struct {
-	store    map[string]*Session
+	store    map[IdentScreenName]*Session
 	mapMutex sync.RWMutex
 	mapMutex sync.RWMutex
 	logger   *slog.Logger
 	logger   *slog.Logger
 }
 }
@@ -21,7 +21,7 @@ type InMemorySessionManager struct {
 func NewInMemorySessionManager(logger *slog.Logger) *InMemorySessionManager {
 func NewInMemorySessionManager(logger *slog.Logger) *InMemorySessionManager {
 	return &InMemorySessionManager{
 	return &InMemorySessionManager{
 		logger: logger,
 		logger: logger,
-		store:  make(map[string]*Session),
+		store:  make(map[IdentScreenName]*Session),
 	}
 	}
 }
 }
 
 
@@ -48,7 +48,7 @@ func (s *InMemorySessionManager) RelayToAllExcept(ctx context.Context, except *S
 }
 }
 
 
 // RelayToScreenName relays a message to a session with a matching screen name.
 // RelayToScreenName relays a message to a session with a matching screen name.
-func (s *InMemorySessionManager) RelayToScreenName(ctx context.Context, screenName string, msg wire.SNACMessage) {
+func (s *InMemorySessionManager) RelayToScreenName(ctx context.Context, screenName IdentScreenName, msg wire.SNACMessage) {
 	sess := s.RetrieveByScreenName(screenName)
 	sess := s.RetrieveByScreenName(screenName)
 	if sess == nil {
 	if sess == nil {
 		s.logger.WarnContext(ctx, "can't send notification because user is not online", "recipient", screenName, "message", msg)
 		s.logger.WarnContext(ctx, "can't send notification because user is not online", "recipient", screenName, "message", msg)
@@ -58,7 +58,7 @@ func (s *InMemorySessionManager) RelayToScreenName(ctx context.Context, screenNa
 }
 }
 
 
 // RelayToScreenNames relays a message to sessions with matching screenNames.
 // RelayToScreenNames relays a message to sessions with matching screenNames.
-func (s *InMemorySessionManager) RelayToScreenNames(ctx context.Context, screenNames []string, msg wire.SNACMessage) {
+func (s *InMemorySessionManager) RelayToScreenNames(ctx context.Context, screenNames []IdentScreenName, msg wire.SNACMessage) {
 	for _, sess := range s.retrieveByScreenNames(screenNames) {
 	for _, sess := range s.retrieveByScreenNames(screenNames) {
 		s.maybeRelayMessage(ctx, msg, sess)
 		s.maybeRelayMessage(ctx, msg, sess)
 	}
 	}
@@ -67,9 +67,9 @@ func (s *InMemorySessionManager) RelayToScreenNames(ctx context.Context, screenN
 func (s *InMemorySessionManager) maybeRelayMessage(ctx context.Context, msg wire.SNACMessage, sess *Session) {
 func (s *InMemorySessionManager) maybeRelayMessage(ctx context.Context, msg wire.SNACMessage, sess *Session) {
 	switch sess.RelayMessage(msg) {
 	switch sess.RelayMessage(msg) {
 	case SessSendClosed:
 	case SessSendClosed:
-		s.logger.WarnContext(ctx, "can't send notification because the user's session is closed", "recipient", sess.ScreenName(), "message", msg)
+		s.logger.WarnContext(ctx, "can't send notification because the user's session is closed", "recipient", sess.IdentScreenName(), "message", msg)
 	case SessQueueFull:
 	case SessQueueFull:
-		s.logger.WarnContext(ctx, "can't send notification because queue is full", "recipient", sess.ScreenName(), "message", msg)
+		s.logger.WarnContext(ctx, "can't send notification because queue is full", "recipient", sess.IdentScreenName(), "message", msg)
 		sess.Close()
 		sess.Close()
 	}
 	}
 }
 }
@@ -77,26 +77,28 @@ func (s *InMemorySessionManager) maybeRelayMessage(ctx context.Context, msg wire
 // AddSession adds a new session to the pool. It replaces an existing session
 // AddSession adds a new session to the pool. It replaces an existing session
 // with a matching screen name, ensuring that each screen name is unique in the
 // with a matching screen name, ensuring that each screen name is unique in the
 // pool.
 // pool.
-func (s *InMemorySessionManager) AddSession(screenName string) *Session {
+func (s *InMemorySessionManager) AddSession(displayScreenName DisplayScreenName) *Session {
 	s.mapMutex.Lock()
 	s.mapMutex.Lock()
 	defer s.mapMutex.Unlock()
 	defer s.mapMutex.Unlock()
 
 
+	identScreenName := NewIdentScreenName(string(displayScreenName))
 	// Only allow one session at a time per screen name. A session may already
 	// Only allow one session at a time per screen name. A session may already
 	// exist because:
 	// exist because:
 	// 1) the user is signing on using an already logged-on screen name.
 	// 1) the user is signing on using an already logged-on screen name.
 	// 2) the session might be orphaned due to an undetected client
 	// 2) the session might be orphaned due to an undetected client
 	// disconnection.
 	// disconnection.
 	for _, sess := range s.store {
 	for _, sess := range s.store {
-		if screenName == sess.ScreenName() {
+		if identScreenName == sess.IdentScreenName() {
 			sess.Close()
 			sess.Close()
-			delete(s.store, screenName)
+			delete(s.store, identScreenName)
 			break
 			break
 		}
 		}
 	}
 	}
 
 
 	sess := NewSession()
 	sess := NewSession()
-	sess.SetScreenName(screenName)
-	s.store[sess.ScreenName()] = sess
+	sess.SetIdentScreenName(identScreenName)
+	sess.SetDisplayScreenName(displayScreenName)
+	s.store[identScreenName] = sess
 	return sess
 	return sess
 }
 }
 
 
@@ -104,37 +106,37 @@ func (s *InMemorySessionManager) AddSession(screenName string) *Session {
 func (s *InMemorySessionManager) RemoveSession(sess *Session) {
 func (s *InMemorySessionManager) RemoveSession(sess *Session) {
 	s.mapMutex.Lock()
 	s.mapMutex.Lock()
 	defer s.mapMutex.Unlock()
 	defer s.mapMutex.Unlock()
-	delete(s.store, sess.ScreenName())
+	delete(s.store, sess.IdentScreenName())
 }
 }
 
 
 // RetrieveSession finds a session with a matching sessionID. Returns nil if
 // RetrieveSession finds a session with a matching sessionID. Returns nil if
 // session is not found.
 // session is not found.
-func (s *InMemorySessionManager) RetrieveSession(sessionID string) *Session {
+func (s *InMemorySessionManager) RetrieveSession(screenName IdentScreenName) *Session {
 	s.mapMutex.RLock()
 	s.mapMutex.RLock()
 	defer s.mapMutex.RUnlock()
 	defer s.mapMutex.RUnlock()
-	return s.store[sessionID]
+	return s.store[screenName]
 }
 }
 
 
 // RetrieveByScreenName find a session with a matching screen name. Returns nil
 // RetrieveByScreenName find a session with a matching screen name. Returns nil
 // if session is not found.
 // if session is not found.
-func (s *InMemorySessionManager) RetrieveByScreenName(screenName string) *Session {
+func (s *InMemorySessionManager) RetrieveByScreenName(screenName IdentScreenName) *Session {
 	s.mapMutex.RLock()
 	s.mapMutex.RLock()
 	defer s.mapMutex.RUnlock()
 	defer s.mapMutex.RUnlock()
 	for _, sess := range s.store {
 	for _, sess := range s.store {
-		if screenName == sess.ScreenName() {
+		if screenName == sess.IdentScreenName() {
 			return sess
 			return sess
 		}
 		}
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
-func (s *InMemorySessionManager) retrieveByScreenNames(screenNames []string) []*Session {
+func (s *InMemorySessionManager) retrieveByScreenNames(screenNames []IdentScreenName) []*Session {
 	s.mapMutex.RLock()
 	s.mapMutex.RLock()
 	defer s.mapMutex.RUnlock()
 	defer s.mapMutex.RUnlock()
 	var ret []*Session
 	var ret []*Session
 	for _, sn := range screenNames {
 	for _, sn := range screenNames {
 		for _, sess := range s.store {
 		for _, sess := range s.store {
-			if sn == sess.ScreenName() {
+			if sn == sess.IdentScreenName() {
 				ret = append(ret, sess)
 				ret = append(ret, sess)
 			}
 			}
 		}
 		}

+ 43 - 52
state/session_manager_test.go

@@ -14,11 +14,11 @@ func TestInMemorySessionManager_AddSession(t *testing.T) {
 	sm := NewInMemorySessionManager(slog.Default())
 	sm := NewInMemorySessionManager(slog.Default())
 
 
 	want1 := sm.AddSession("user-screen-name")
 	want1 := sm.AddSession("user-screen-name")
-	have1 := sm.RetrieveByScreenName("user-screen-name")
+	have1 := sm.RetrieveByScreenName(NewIdentScreenName("user-screen-name"))
 	assert.Same(t, want1, have1)
 	assert.Same(t, want1, have1)
 
 
 	want2 := sm.AddSession("user-screen-name")
 	want2 := sm.AddSession("user-screen-name")
-	have2 := sm.RetrieveByScreenName("user-screen-name")
+	have2 := sm.RetrieveByScreenName(NewIdentScreenName("user-screen-name"))
 	assert.Same(t, want2, have2)
 	assert.Same(t, want2, have2)
 
 
 	// ensure that the second session created with the same screen name as the
 	// ensure that the second session created with the same screen name as the
@@ -29,38 +29,34 @@ func TestInMemorySessionManager_AddSession(t *testing.T) {
 func TestInMemorySessionManager_Remove(t *testing.T) {
 func TestInMemorySessionManager_Remove(t *testing.T) {
 	tests := []struct {
 	tests := []struct {
 		name   string
 		name   string
-		given  []*Session
-		remove string
-		want   []string
+		given  []DisplayScreenName
+		remove IdentScreenName
+		want   []IdentScreenName
 	}{
 	}{
 		{
 		{
 			name: "remove user that exists",
 			name: "remove user that exists",
-			given: []*Session{
-				{
-					screenName: "user-screen-name-1",
-				},
-				{
-					screenName: "user-screen-name-2",
-				},
-			},
-			remove: "user-screen-name-1",
-			want: []string{
+			given: []DisplayScreenName{
+				"user-screen-name-1",
 				"user-screen-name-2",
 				"user-screen-name-2",
 			},
 			},
+			remove: NewIdentScreenName("user-screen-name-1"),
+			want: []IdentScreenName{
+				NewIdentScreenName("user-screen-name-2"),
+			},
 		},
 		},
 	}
 	}
 	for _, tt := range tests {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			sm := NewInMemorySessionManager(slog.Default())
 			sm := NewInMemorySessionManager(slog.Default())
 
 
-			for _, sess := range tt.given {
-				sm.AddSession(sess.screenName)
+			for _, screenName := range tt.given {
+				sm.AddSession(screenName)
 			}
 			}
 
 
 			sm.RemoveSession(sm.RetrieveByScreenName(tt.remove))
 			sm.RemoveSession(sm.RetrieveByScreenName(tt.remove))
 
 
 			for i, sess := range sm.AllSessions() {
 			for i, sess := range sm.AllSessions() {
-				assert.Equal(t, tt.want[i], sess.screenName)
+				assert.Equal(t, tt.want[i], sess.identScreenName)
 			}
 			}
 		})
 		})
 	}
 	}
@@ -68,23 +64,20 @@ func TestInMemorySessionManager_Remove(t *testing.T) {
 
 
 func TestInMemorySessionManager_Empty(t *testing.T) {
 func TestInMemorySessionManager_Empty(t *testing.T) {
 	tests := []struct {
 	tests := []struct {
-		name   string
-		given  []*Session
-		remove string
-		want   bool
+		name  string
+		given []DisplayScreenName
+		want  bool
 	}{
 	}{
 		{
 		{
 			name: "session manager is not empty",
 			name: "session manager is not empty",
-			given: []*Session{
-				{
-					screenName: "user-screen-name-1",
-				},
+			given: []DisplayScreenName{
+				"user-screen-name-1",
 			},
 			},
 			want: false,
 			want: false,
 		},
 		},
 		{
 		{
 			name:  "session manager is empty",
 			name:  "session manager is empty",
-			given: []*Session{},
+			given: []DisplayScreenName{},
 			want:  true,
 			want:  true,
 		},
 		},
 	}
 	}
@@ -92,8 +85,8 @@ func TestInMemorySessionManager_Empty(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			sm := NewInMemorySessionManager(slog.Default())
 			sm := NewInMemorySessionManager(slog.Default())
 
 
-			for _, sess := range tt.given {
-				sm.AddSession(sess.screenName)
+			for _, screenName := range tt.given {
+				sm.AddSession(screenName)
 			}
 			}
 
 
 			have := sm.Empty()
 			have := sm.Empty()
@@ -105,44 +98,39 @@ func TestInMemorySessionManager_Empty(t *testing.T) {
 func TestInMemorySessionManager_Retrieve(t *testing.T) {
 func TestInMemorySessionManager_Retrieve(t *testing.T) {
 	tests := []struct {
 	tests := []struct {
 		name             string
 		name             string
-		given            []*Session
-		lookupScreenName string
-		remove           string
-		wantScreenName   string
+		given            []DisplayScreenName
+		lookupScreenName IdentScreenName
+		wantScreenName   IdentScreenName
 	}{
 	}{
 		{
 		{
 			name: "lookup finds match",
 			name: "lookup finds match",
-			given: []*Session{
-				{
-					screenName: "user-screen-name-1",
-				},
-				{
-					screenName: "user-screen-name-2",
-				},
+			given: []DisplayScreenName{
+				"user-screen-name-1",
+				"user-screen-name-2",
 			},
 			},
-			lookupScreenName: "user-screen-name-2",
-			wantScreenName:   "user-screen-name-2",
+			lookupScreenName: NewIdentScreenName("user-screen-name-2"),
+			wantScreenName:   NewIdentScreenName("user-screen-name-2"),
 		},
 		},
 		{
 		{
 			name:             "lookup does not find match",
 			name:             "lookup does not find match",
-			given:            []*Session{},
-			lookupScreenName: "user-screen-name-3",
-			wantScreenName:   "",
+			given:            []DisplayScreenName{},
+			lookupScreenName: NewIdentScreenName("user-screen-name-3"),
+			wantScreenName:   NewIdentScreenName(""),
 		},
 		},
 	}
 	}
 	for _, tt := range tests {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			sm := NewInMemorySessionManager(slog.Default())
 			sm := NewInMemorySessionManager(slog.Default())
 
 
-			for _, sess := range tt.given {
-				sm.AddSession(sess.screenName)
+			for _, screenName := range tt.given {
+				sm.AddSession(screenName)
 			}
 			}
 
 
 			have := sm.RetrieveSession(tt.lookupScreenName)
 			have := sm.RetrieveSession(tt.lookupScreenName)
 			if have == nil {
 			if have == nil {
 				assert.Empty(t, tt.wantScreenName)
 				assert.Empty(t, tt.wantScreenName)
 			} else {
 			} else {
-				assert.Equal(t, tt.wantScreenName, have.ScreenName())
+				assert.Equal(t, tt.wantScreenName, have.IdentScreenName())
 			}
 			}
 		})
 		})
 	}
 	}
@@ -157,7 +145,10 @@ func TestInMemorySessionManager_RelayToScreenNames(t *testing.T) {
 
 
 	want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
 	want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
 
 
-	recips := []string{"user-screen-name-1", "user-screen-name-2"}
+	recips := []IdentScreenName{
+		NewIdentScreenName("user-screen-name-1"),
+		NewIdentScreenName("user-screen-name-2"),
+	}
 	sm.RelayToScreenNames(context.Background(), recips, want)
 	sm.RelayToScreenNames(context.Background(), recips, want)
 
 
 	select {
 	select {
@@ -229,7 +220,7 @@ func TestInMemorySessionManager_RelayToScreenName_SessionExists(t *testing.T) {
 
 
 	want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
 	want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
 
 
-	recip := "user-screen-name-1"
+	recip := NewIdentScreenName("user-screen-name-1")
 	sm.RelayToScreenName(context.Background(), recip, want)
 	sm.RelayToScreenName(context.Background(), recip, want)
 
 
 	select {
 	select {
@@ -251,7 +242,7 @@ func TestInMemorySessionManager_RelayToScreenName_SessionNotExist(t *testing.T)
 
 
 	want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
 	want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
 
 
-	recip := "user-screen-name-2"
+	recip := NewIdentScreenName("user-screen-name-2")
 	sm.RelayToScreenName(context.Background(), recip, want)
 	sm.RelayToScreenName(context.Background(), recip, want)
 
 
 	select {
 	select {
@@ -275,7 +266,7 @@ func TestInMemorySessionManager_RelayToScreenName_SkipFullSession(t *testing.T)
 		wantCount++
 		wantCount++
 	}
 	}
 
 
-	recip := "user-screen-name-1"
+	recip := NewIdentScreenName("user-screen-name-1")
 	sm.RelayToScreenName(context.Background(), recip, msg)
 	sm.RelayToScreenName(context.Background(), recip, msg)
 
 
 	haveCount := 0
 	haveCount := 0

+ 6 - 5
state/session_test.go

@@ -38,10 +38,10 @@ func TestSession_SetAndGetInvisible(t *testing.T) {
 
 
 func TestSession_SetAndGetScreenName(t *testing.T) {
 func TestSession_SetAndGetScreenName(t *testing.T) {
 	s := NewSession()
 	s := NewSession()
-	assert.Empty(t, s.ScreenName())
-	sn := "user-screen-name"
-	s.SetScreenName(sn)
-	assert.Equal(t, sn, s.ScreenName())
+	assert.Empty(t, s.IdentScreenName())
+	sn := NewIdentScreenName("user-screen-name")
+	s.SetIdentScreenName(sn)
+	assert.Equal(t, sn, s.IdentScreenName())
 }
 }
 
 
 func TestSession_SetAndGetChatRoomCookie(t *testing.T) {
 func TestSession_SetAndGetChatRoomCookie(t *testing.T) {
@@ -63,7 +63,8 @@ func TestSession_TLVUserInfo(t *testing.T) {
 			givenSessionFn: func() *Session {
 			givenSessionFn: func() *Session {
 				s := NewSession()
 				s := NewSession()
 				s.SetSignonTime(time.Unix(1, 0))
 				s.SetSignonTime(time.Unix(1, 0))
-				s.SetScreenName("xXAIMUSERXx")
+				s.SetIdentScreenName(NewIdentScreenName("xXAIMUSERXx"))
+				s.SetDisplayScreenName("xXAIMUSERXx")
 				s.IncrementWarning(10)
 				s.IncrementWarning(10)
 				return s
 				return s
 			},
 			},

+ 122 - 0
state/user.go

@@ -0,0 +1,122 @@
+package state
+
+import (
+	"bytes"
+	"errors"
+	"strings"
+
+	"github.com/google/uuid"
+
+	"github.com/mk6i/retro-aim-server/wire"
+)
+
+// BlockedState represents the blocked status between two users
+type BlockedState int
+
+var (
+	// ErrDupUser indicates that a user already exists.
+	ErrDupUser = errors.New("user already exists")
+	// ErrNoUser indicates that a user does not exist.
+	ErrNoUser = errors.New("user does not exist")
+)
+
+const (
+	// BlockedNo indicates that neither user blocks the other.
+	BlockedNo BlockedState = iota
+	// BlockedA indicates that user A blocks user B.
+	BlockedA
+	// BlockedB indicates that user B blocks user A.
+	BlockedB
+)
+
+// IdentScreenName struct stores the normalized version of a user's screen name.
+// This format is used for uniformity in storage and comparison by removing spaces
+// and converting all characters to lowercase.
+type IdentScreenName struct {
+	// screenName contains the identifier screen name value. Do not assign this
+	// value directly. Rather, set it through NewIdentScreenName. This ensures
+	// that when an instance of IdentScreenName is present, it's guaranteed to
+	// have a normalized value.
+	screenName string
+}
+
+// String returns the string representation of the IdentScreenName.
+func (i IdentScreenName) String() string {
+	return i.screenName
+}
+
+// NewIdentScreenName creates a new IdentScreenName.
+func NewIdentScreenName(screenName string) IdentScreenName {
+	str := strings.ReplaceAll(screenName, " ", "")
+	str = strings.ToLower(str)
+	return IdentScreenName{screenName: str}
+}
+
+// DisplayScreenName type represents the screen name in the user-defined format.
+// This includes the original casing and spacing as defined by the user.
+type DisplayScreenName string
+
+// IdentScreenName converts the DisplayScreenName to an IdentScreenName by applying
+// the normalization process defined in NewIdentScreenName.
+func (s DisplayScreenName) IdentScreenName() IdentScreenName {
+	return NewIdentScreenName(string(s))
+}
+
+// String returns the original display string of the screen name, preserving the user-defined
+// casing and spaces.
+func (s DisplayScreenName) String() string {
+	return string(s)
+}
+
+// NewStubUser creates a new user with canned credentials. The default password
+// is "welcome1". This is typically used for development purposes.
+func NewStubUser(screenName DisplayScreenName) (User, error) {
+	uid, err := uuid.NewRandom()
+	if err != nil {
+		return User{}, err
+	}
+	u := User{
+		IdentScreenName:   NewIdentScreenName(string(screenName)),
+		DisplayScreenName: screenName,
+		AuthKey:           uid.String(),
+	}
+	err = u.HashPassword("welcome1")
+	return u, err
+}
+
+// User represents a user account.
+type User struct {
+	// IdentScreenName is the AIM screen name.
+	IdentScreenName IdentScreenName `json:"-"`
+	// DisplayScreenName is the formatted screen name.
+	DisplayScreenName DisplayScreenName `json:"screen_name"`
+	// AuthKey is the salt for the MD5 password hash.
+	AuthKey string `json:"-"`
+	// StrongMD5Pass is the MD5 password hash format used by AIM v4.8-v5.9.
+	StrongMD5Pass []byte `json:"-"`
+	// WeakMD5Pass is the MD5 password hash format used by AIM v3.5-v4.7. This
+	// hash is used to authenticate roasted passwords for AIM v1.0-v3.0.
+	WeakMD5Pass []byte `json:"-"`
+}
+
+// ValidateHash checks if md5Hash is identical to one of the password hashes.
+func (u *User) ValidateHash(md5Hash []byte) bool {
+	return bytes.Equal(u.StrongMD5Pass, md5Hash) || bytes.Equal(u.WeakMD5Pass, md5Hash)
+}
+
+// ValidateRoastedPass checks if the provided roasted password matches the MD5
+// hash of the user's actual password. A roasted password is a XOR-obfuscated
+// form of the real password, intended to add a simple layer of security.
+func (u *User) ValidateRoastedPass(roastedPass []byte) bool {
+	clearPass := wire.RoastPassword(roastedPass)
+	md5Hash := wire.WeakMD5PasswordHash(string(clearPass), u.AuthKey) // todo remove string conversion
+	return bytes.Equal(u.WeakMD5Pass, md5Hash)
+}
+
+// HashPassword computes MD5 hashes of the user's password. It computes both
+// weak and strong variants and stores them in the struct.
+func (u *User) HashPassword(passwd string) error {
+	u.WeakMD5Pass = wire.WeakMD5PasswordHash(passwd, u.AuthKey)
+	u.StrongMD5Pass = wire.StrongMD5PasswordHash(passwd, u.AuthKey)
+	return nil
+}

+ 68 - 123
state/user_store.go

@@ -15,67 +15,12 @@ import (
 	"github.com/golang-migrate/migrate/v4"
 	"github.com/golang-migrate/migrate/v4"
 	"github.com/golang-migrate/migrate/v4/database/sqlite3"
 	"github.com/golang-migrate/migrate/v4/database/sqlite3"
 	"github.com/golang-migrate/migrate/v4/source/httpfs"
 	"github.com/golang-migrate/migrate/v4/source/httpfs"
-	"github.com/google/uuid"
 	_ "github.com/mattn/go-sqlite3"
 	_ "github.com/mattn/go-sqlite3"
 )
 )
 
 
-// BlockedState represents the blocked status between two users
-type BlockedState int
-
 //go:embed migrations/*
 //go:embed migrations/*
 var migrations embed.FS
 var migrations embed.FS
 
 
-var (
-	// ErrDupUser indicates that a user already exists.
-	ErrDupUser = errors.New("user already exists")
-	// ErrNoUser indicates that a user does not exist.
-	ErrNoUser = errors.New("user does not exist")
-)
-
-const (
-	// BlockedNo indicates that neither user blocks the other.
-	BlockedNo BlockedState = iota
-	// BlockedA indicates that user A blocks user B.
-	BlockedA
-	// BlockedB indicates that user B blocks user A.
-	BlockedB
-)
-
-// User represents a user account.
-type User struct {
-	// ScreenName is the AIM screen name.
-	ScreenName string `json:"screen_name"`
-	// AuthKey is the salt for the MD5 password hash.
-	AuthKey string `json:"-"`
-	// StrongMD5Pass is the MD5 password hash format used by AIM v4.8-v5.9.
-	StrongMD5Pass []byte `json:"-"`
-	// WeakMD5Pass is the MD5 password hash format used by AIM v3.5-v4.7. This
-	// hash is used to authenticate roasted passwords for AIM v1.0-v3.0.
-	WeakMD5Pass []byte `json:"-"`
-}
-
-// ValidateHash checks if md5Hash is identical to one of the password hashes.
-func (u *User) ValidateHash(md5Hash []byte) bool {
-	return bytes.Equal(u.StrongMD5Pass, md5Hash) || bytes.Equal(u.WeakMD5Pass, md5Hash)
-}
-
-// ValidateRoastedPass checks if the provided roasted password matches the MD5
-// hash of the user's actual password. A roasted password is a XOR-obfuscated
-// form of the real password, intended to add a simple layer of security.
-func (u *User) ValidateRoastedPass(roastedPass []byte) bool {
-	clearPass := wire.RoastPassword(roastedPass)
-	md5Hash := wire.WeakMD5PasswordHash(string(clearPass), u.AuthKey) // todo remove string conversion
-	return bytes.Equal(u.WeakMD5Pass, md5Hash)
-}
-
-// HashPassword computes MD5 hashes of the user's password. It computes both
-// weak and strong variants and stores them in the struct.
-func (u *User) HashPassword(passwd string) error {
-	u.WeakMD5Pass = wire.WeakMD5PasswordHash(passwd, u.AuthKey)
-	u.StrongMD5Pass = wire.StrongMD5PasswordHash(passwd, u.AuthKey)
-	return nil
-}
-
 // SQLiteUserStore stores user feedbag (buddy list), profile, and
 // SQLiteUserStore stores user feedbag (buddy list), profile, and
 // authentication credentials information in a SQLite database.
 // authentication credentials information in a SQLite database.
 type SQLiteUserStore struct {
 type SQLiteUserStore struct {
@@ -122,10 +67,10 @@ func (f SQLiteUserStore) runMigrations() error {
 	return nil
 	return nil
 }
 }
 
 
-// AllUsers returns all stored users. It only populates the User.ScreenName field
-// populated in the returned slice.
+// AllUsers returns all stored users. It only populates the User.IdentScreenName and
+// User.DisplayScreenName fields in the return slice.
 func (f SQLiteUserStore) AllUsers() ([]User, error) {
 func (f SQLiteUserStore) AllUsers() ([]User, error) {
-	q := `SELECT screenName FROM user`
+	q := `SELECT identScreenName, displayScreenName FROM users`
 	rows, err := f.db.Query(q)
 	rows, err := f.db.Query(q)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -134,11 +79,14 @@ func (f SQLiteUserStore) AllUsers() ([]User, error) {
 
 
 	var users []User
 	var users []User
 	for rows.Next() {
 	for rows.Next() {
-		u := User{}
-		if err := rows.Scan(&u.ScreenName); err != nil {
+		var identSN, displaySN string
+		if err := rows.Scan(&identSN, &displaySN); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		users = append(users, u)
+		users = append(users, User{
+			IdentScreenName:   NewIdentScreenName(identSN),
+			DisplayScreenName: DisplayScreenName(displaySN),
+		})
 	}
 	}
 
 
 	if err := rows.Err(); err != nil {
 	if err := rows.Err(); err != nil {
@@ -150,18 +98,22 @@ func (f SQLiteUserStore) AllUsers() ([]User, error) {
 
 
 // User looks up a user by screen name. It populates the User record with
 // User looks up a user by screen name. It populates the User record with
 // credentials that can be used to validate the user's password.
 // credentials that can be used to validate the user's password.
-func (f SQLiteUserStore) User(screenName string) (*User, error) {
+func (f SQLiteUserStore) User(screenName IdentScreenName) (*User, error) {
 	q := `
 	q := `
 		SELECT
 		SELECT
-			screenName, 
-			authKey, 
+			displayScreenName,
+			authKey,
 			weakMD5Pass,
 			weakMD5Pass,
 			strongMD5Pass
 			strongMD5Pass
-		FROM user
-		WHERE screenName = ?
+		FROM users
+		WHERE identScreenName = ?
 	`
 	`
-	u := &User{}
-	err := f.db.QueryRow(q, screenName).Scan(&u.ScreenName, &u.AuthKey, &u.WeakMD5Pass, &u.StrongMD5Pass)
+	u := &User{
+		IdentScreenName: screenName,
+	}
+	err := f.db.QueryRow(q, screenName.String()).
+		Scan(&u.DisplayScreenName, &u.AuthKey, &u.WeakMD5Pass, &u.StrongMD5Pass)
+
 	if errors.Is(err, sql.ErrNoRows) {
 	if errors.Is(err, sql.ErrNoRows) {
 		return nil, nil
 		return nil, nil
 	}
 	}
@@ -172,11 +124,11 @@ func (f SQLiteUserStore) User(screenName string) (*User, error) {
 // same screen name already exists.
 // same screen name already exists.
 func (f SQLiteUserStore) InsertUser(u User) error {
 func (f SQLiteUserStore) InsertUser(u User) error {
 	q := `
 	q := `
-		INSERT INTO user (screenName, authKey, weakMD5Pass, strongMD5Pass)
-		VALUES (?, ?, ?, ?)
-		ON CONFLICT (screenName) DO NOTHING
+		INSERT INTO users (identScreenName, displayScreenName, authKey, weakMD5Pass, strongMD5Pass)
+		VALUES (?, ?, ?, ?, ?)
+		ON CONFLICT (identScreenName) DO NOTHING
 	`
 	`
-	result, err := f.db.Exec(q, u.ScreenName, u.AuthKey, u.WeakMD5Pass, u.StrongMD5Pass)
+	result, err := f.db.Exec(q, u.IdentScreenName.String(), u.DisplayScreenName, u.AuthKey, u.WeakMD5Pass, u.StrongMD5Pass)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -194,11 +146,11 @@ func (f SQLiteUserStore) InsertUser(u User) error {
 
 
 // DeleteUser deletes a user from the store. Return ErrNoUser if the user did
 // DeleteUser deletes a user from the store. Return ErrNoUser if the user did
 // not exist prior to deletion.
 // not exist prior to deletion.
-func (f SQLiteUserStore) DeleteUser(screenName string) error {
+func (f SQLiteUserStore) DeleteUser(screenName IdentScreenName) error {
 	q := `
 	q := `
-		DELETE FROM user WHERE screenName = ?
+		DELETE FROM users WHERE identScreenName = ?
 	`
 	`
-	result, err := f.db.Exec(q, screenName)
+	result, err := f.db.Exec(q, screenName.String())
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -215,43 +167,44 @@ func (f SQLiteUserStore) DeleteUser(screenName string) error {
 }
 }
 
 
 // SetUserPassword sets the user's password hashes and auth key.
 // SetUserPassword sets the user's password hashes and auth key.
-func (f SQLiteUserStore) SetUserPassword(u User) error {
+func (f SQLiteUserStore) SetUserPassword(u User) (err error) {
 	tx, err := f.db.Begin()
 	tx, err := f.db.Begin()
 	if err != nil {
 	if err != nil {
-		return err
+		return
 	}
 	}
 
 
 	defer func() {
 	defer func() {
 		if err != nil {
 		if err != nil {
-			tx.Rollback()
+			err = errors.Join(err, tx.Rollback())
 		}
 		}
 	}()
 	}()
 
 
 	q := `
 	q := `
-		UPDATE user
+		UPDATE users
 		SET authKey = ?, weakMD5Pass = ?, strongMD5Pass = ?
 		SET authKey = ?, weakMD5Pass = ?, strongMD5Pass = ?
-		WHERE screenName = ?
+		WHERE identScreenName = ?
 	`
 	`
-	result, err := tx.Exec(q, u.AuthKey, u.WeakMD5Pass, u.StrongMD5Pass, u.ScreenName)
+	result, err := tx.Exec(q, u.AuthKey, u.WeakMD5Pass, u.StrongMD5Pass, u.IdentScreenName.String())
 	if err != nil {
 	if err != nil {
-		return err
+		return
 	}
 	}
 
 
 	rowsAffected, err := result.RowsAffected()
 	rowsAffected, err := result.RowsAffected()
 	if err != nil {
 	if err != nil {
-		return err
+		return
 	}
 	}
 
 
 	if rowsAffected == 0 {
 	if rowsAffected == 0 {
 		// it's possible the user didn't change OR the user doesn't exist.
 		// it's possible the user didn't change OR the user doesn't exist.
 		// check if the user exists.
 		// check if the user exists.
 		var exists int
 		var exists int
-		err = tx.QueryRow("SELECT COUNT(*) FROM user WHERE screenName = ?", u.ScreenName).Scan(&exists)
+		err = tx.QueryRow("SELECT COUNT(*) FROM users WHERE identScreenName = ?", u.IdentScreenName.String()).Scan(&exists)
 		if err != nil {
 		if err != nil {
-			return err // Handle possible SQL errors during the select
+			return // Handle possible SQL errors during the select
 		}
 		}
 		if exists == 0 {
 		if exists == 0 {
-			return ErrNoUser // User does not exist
+			err = ErrNoUser // User does not exist
+			return
 		}
 		}
 	}
 	}
 
 
@@ -259,7 +212,7 @@ func (f SQLiteUserStore) SetUserPassword(u User) error {
 }
 }
 
 
 // Feedbag fetches the contents of a user's feedbag (buddy list).
 // Feedbag fetches the contents of a user's feedbag (buddy list).
-func (f SQLiteUserStore) Feedbag(screenName string) ([]wire.FeedbagItem, error) {
+func (f SQLiteUserStore) Feedbag(screenName IdentScreenName) ([]wire.FeedbagItem, error) {
 	q := `
 	q := `
 		SELECT 
 		SELECT 
 			groupID,
 			groupID,
@@ -271,7 +224,7 @@ func (f SQLiteUserStore) Feedbag(screenName string) ([]wire.FeedbagItem, error)
 		WHERE screenName = ?
 		WHERE screenName = ?
 	`
 	`
 
 
-	rows, err := f.db.Query(q, screenName)
+	rows, err := f.db.Query(q, screenName.String())
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -295,20 +248,20 @@ func (f SQLiteUserStore) Feedbag(screenName string) ([]wire.FeedbagItem, error)
 
 
 // FeedbagLastModified returns the last time a user's feedbag (buddy list) was
 // FeedbagLastModified returns the last time a user's feedbag (buddy list) was
 // updated.
 // updated.
-func (f SQLiteUserStore) FeedbagLastModified(screenName string) (time.Time, error) {
+func (f SQLiteUserStore) FeedbagLastModified(screenName IdentScreenName) (time.Time, error) {
 	var lastModified sql.NullInt64
 	var lastModified sql.NullInt64
 	q := `SELECT MAX(lastModified) FROM feedbag WHERE screenName = ?`
 	q := `SELECT MAX(lastModified) FROM feedbag WHERE screenName = ?`
-	err := f.db.QueryRow(q, screenName).Scan(&lastModified)
+	err := f.db.QueryRow(q, screenName.String()).Scan(&lastModified)
 	return time.Unix(lastModified.Int64, 0), err
 	return time.Unix(lastModified.Int64, 0), err
 }
 }
 
 
 // FeedbagDelete deletes an entry from a user's feedbag (buddy list).
 // FeedbagDelete deletes an entry from a user's feedbag (buddy list).
-func (f SQLiteUserStore) FeedbagDelete(screenName string, items []wire.FeedbagItem) error {
+func (f SQLiteUserStore) FeedbagDelete(screenName IdentScreenName, items []wire.FeedbagItem) error {
 	// todo add transaction
 	// todo add transaction
 	q := `DELETE FROM feedbag WHERE screenName = ? AND itemID = ?`
 	q := `DELETE FROM feedbag WHERE screenName = ? AND itemID = ?`
 
 
 	for _, item := range items {
 	for _, item := range items {
-		if _, err := f.db.Exec(q, screenName, item.ItemID); err != nil {
+		if _, err := f.db.Exec(q, screenName.String(), item.ItemID); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -318,7 +271,7 @@ func (f SQLiteUserStore) FeedbagDelete(screenName string, items []wire.FeedbagIt
 
 
 // FeedbagUpsert upserts an entry to a user's feedbag (buddy list). An entry is
 // FeedbagUpsert upserts an entry to a user's feedbag (buddy list). An entry is
 // created if it doesn't already exist, or modified if it already exists.
 // created if it doesn't already exist, or modified if it already exists.
-func (f SQLiteUserStore) FeedbagUpsert(screenName string, items []wire.FeedbagItem) error {
+func (f SQLiteUserStore) FeedbagUpsert(screenName IdentScreenName, items []wire.FeedbagItem) error {
 	q := `
 	q := `
 		INSERT INTO feedbag (screenName, groupID, itemID, classID, name, attributes, lastModified)
 		INSERT INTO feedbag (screenName, groupID, itemID, classID, name, attributes, lastModified)
 		VALUES (?, ?, ?, ?, ?, ?, UNIXEPOCH())
 		VALUES (?, ?, ?, ?, ?, ?, UNIXEPOCH())
@@ -335,8 +288,15 @@ func (f SQLiteUserStore) FeedbagUpsert(screenName string, items []wire.FeedbagIt
 			return err
 			return err
 		}
 		}
 
 
+		// todo are these all the right items?
+		if item.ClassID == wire.FeedbagClassIdBuddy ||
+			item.ClassID == wire.FeedbagClassIDPermit ||
+			item.ClassID == wire.FeedbagClassIDDeny {
+			// insert screen name identifier
+			item.Name = NewIdentScreenName(item.Name).String()
+		}
 		_, err := f.db.Exec(q,
 		_, err := f.db.Exec(q,
-			screenName,
+			screenName.String(),
 			item.GroupID,
 			item.GroupID,
 			item.ItemID,
 			item.ItemID,
 			item.ClassID,
 			item.ClassID,
@@ -352,7 +312,7 @@ func (f SQLiteUserStore) FeedbagUpsert(screenName string, items []wire.FeedbagIt
 
 
 // AdjacentUsers returns all users who have screenName in their buddy list.
 // AdjacentUsers returns all users who have screenName in their buddy list.
 // Exclude users who are on screenName's block list.
 // Exclude users who are on screenName's block list.
-func (f SQLiteUserStore) AdjacentUsers(screenName string) ([]string, error) {
+func (f SQLiteUserStore) AdjacentUsers(screenName IdentScreenName) ([]IdentScreenName, error) {
 	q := `
 	q := `
 		SELECT f.screenName
 		SELECT f.screenName
 		FROM feedbag f
 		FROM feedbag f
@@ -364,19 +324,19 @@ func (f SQLiteUserStore) AdjacentUsers(screenName string) ([]string, error) {
 		AND NOT EXISTS(SELECT 1 FROM feedbag WHERE screenName = f.screenName AND name = f.name AND classID = 3)
 		AND NOT EXISTS(SELECT 1 FROM feedbag WHERE screenName = f.screenName AND name = f.name AND classID = 3)
 	`
 	`
 
 
-	rows, err := f.db.Query(q, screenName, screenName, screenName)
+	rows, err := f.db.Query(q, screenName.String(), screenName.String(), screenName.String())
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	defer rows.Close()
 	defer rows.Close()
 
 
-	var items []string
+	var items []IdentScreenName
 	for rows.Next() {
 	for rows.Next() {
 		var sn string
 		var sn string
 		if err := rows.Scan(&sn); err != nil {
 		if err := rows.Scan(&sn); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		items = append(items, sn)
+		items = append(items, NewIdentScreenName(sn))
 	}
 	}
 
 
 	return items, nil
 	return items, nil
@@ -384,7 +344,7 @@ func (f SQLiteUserStore) AdjacentUsers(screenName string) ([]string, error) {
 
 
 // Buddies returns all user's buddies. Don't return a buddy if the user has
 // Buddies returns all user's buddies. Don't return a buddy if the user has
 // them on their block list.
 // them on their block list.
-func (f SQLiteUserStore) Buddies(screenName string) ([]string, error) {
+func (f SQLiteUserStore) Buddies(screenName IdentScreenName) ([]IdentScreenName, error) {
 	q := `
 	q := `
 		SELECT f.name
 		SELECT f.name
 		FROM feedbag f
 		FROM feedbag f
@@ -395,26 +355,26 @@ func (f SQLiteUserStore) Buddies(screenName string) ([]string, error) {
 		AND NOT EXISTS(SELECT 1 FROM feedbag WHERE screenName = ? AND name = f.name AND classID = 3)
 		AND NOT EXISTS(SELECT 1 FROM feedbag WHERE screenName = ? AND name = f.name AND classID = 3)
 	`
 	`
 
 
-	rows, err := f.db.Query(q, screenName, screenName, screenName)
+	rows, err := f.db.Query(q, screenName.String(), screenName.String(), screenName.String())
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	defer rows.Close()
 	defer rows.Close()
 
 
-	var items []string
+	var items []IdentScreenName
 	for rows.Next() {
 	for rows.Next() {
 		var sn string
 		var sn string
 		if err := rows.Scan(&sn); err != nil {
 		if err := rows.Scan(&sn); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		items = append(items, sn)
+		items = append(items, NewIdentScreenName(sn))
 	}
 	}
 
 
 	return items, nil
 	return items, nil
 }
 }
 
 
 // BlockedState returns the BlockedState between two users.
 // BlockedState returns the BlockedState between two users.
-func (f SQLiteUserStore) BlockedState(screenNameA, screenNameB string) (BlockedState, error) {
+func (f SQLiteUserStore) BlockedState(screenName1, screenName2 IdentScreenName) (BlockedState, error) {
 	q := `
 	q := `
 		SELECT EXISTS(SELECT 1
 		SELECT EXISTS(SELECT 1
 					  FROM feedbag f
 					  FROM feedbag f
@@ -428,7 +388,7 @@ func (f SQLiteUserStore) BlockedState(screenNameA, screenNameB string) (BlockedS
 						AND f.screenName = ?
 						AND f.screenName = ?
 						AND f.name = ?)
 						AND f.name = ?)
 	`
 	`
-	row, err := f.db.Query(q, screenNameA, screenNameB, screenNameB, screenNameA)
+	row, err := f.db.Query(q, screenName1.String(), screenName2.String(), screenName2.String(), screenName1.String())
 	if err != nil {
 	if err != nil {
 		return BlockedNo, err
 		return BlockedNo, err
 	}
 	}
@@ -460,14 +420,14 @@ func (f SQLiteUserStore) BlockedState(screenNameA, screenNameB string) (BlockedS
 
 
 // Profile fetches a user profile. Return empty string if the user
 // Profile fetches a user profile. Return empty string if the user
 // does not exist or has no profile.
 // does not exist or has no profile.
-func (f SQLiteUserStore) Profile(screenName string) (string, error) {
+func (f SQLiteUserStore) Profile(screenName IdentScreenName) (string, error) {
 	q := `
 	q := `
 		SELECT IFNULL(body, '')
 		SELECT IFNULL(body, '')
 		FROM profile
 		FROM profile
 		WHERE screenName = ?
 		WHERE screenName = ?
 	`
 	`
 	var profile string
 	var profile string
-	err := f.db.QueryRow(q, screenName).Scan(&profile)
+	err := f.db.QueryRow(q, screenName.String()).Scan(&profile)
 	if err != nil && !errors.Is(err, sql.ErrNoRows) {
 	if err != nil && !errors.Is(err, sql.ErrNoRows) {
 		return "", err
 		return "", err
 	}
 	}
@@ -475,14 +435,14 @@ func (f SQLiteUserStore) Profile(screenName string) (string, error) {
 }
 }
 
 
 // SetProfile sets the text contents of a user's profile.
 // SetProfile sets the text contents of a user's profile.
-func (f SQLiteUserStore) SetProfile(screenName string, body string) error {
+func (f SQLiteUserStore) SetProfile(screenName IdentScreenName, body string) error {
 	q := `
 	q := `
 		INSERT INTO profile (screenName, body)
 		INSERT INTO profile (screenName, body)
 		VALUES (?, ?)
 		VALUES (?, ?)
 		ON CONFLICT (screenName)
 		ON CONFLICT (screenName)
 			DO UPDATE SET body = excluded.body
 			DO UPDATE SET body = excluded.body
 	`
 	`
-	_, err := f.db.Exec(q, screenName, body)
+	_, err := f.db.Exec(q, screenName.String(), body)
 	return err
 	return err
 }
 }
 
 
@@ -509,18 +469,3 @@ func (f SQLiteUserStore) BARTRetrieve(hash []byte) ([]byte, error) {
 	}
 	}
 	return body, nil
 	return body, nil
 }
 }
-
-// NewStubUser creates a new user with canned credentials. The default password
-// is "welcome1". This is typically used for development purposes.
-func NewStubUser(screenName string) (User, error) {
-	uid, err := uuid.NewRandom()
-	if err != nil {
-		return User{}, err
-	}
-	u := User{
-		ScreenName: screenName,
-		AuthKey:    uid.String(),
-	}
-	err = u.HashPassword("welcome1")
-	return u, err
-}

+ 213 - 77
state/user_store_test.go

@@ -14,7 +14,7 @@ const testFile string = "aim_test.db"
 
 
 func TestUserStore(t *testing.T) {
 func TestUserStore(t *testing.T) {
 
 
-	const screenName = "sn2day"
+	screenName := NewIdentScreenName("sn2day")
 
 
 	defer func() {
 	defer func() {
 		assert.NoError(t, os.Remove(testFile))
 		assert.NoError(t, os.Remove(testFile))
@@ -54,7 +54,7 @@ func TestUserStore(t *testing.T) {
 
 
 func TestFeedbagDelete(t *testing.T) {
 func TestFeedbagDelete(t *testing.T) {
 
 
-	const screenName = "sn2day"
+	screenName := NewIdentScreenName("sn2day")
 
 
 	defer func() {
 	defer func() {
 		assert.NoError(t, os.Remove(testFile))
 		assert.NoError(t, os.Remove(testFile))
@@ -111,7 +111,7 @@ func TestFeedbagDelete(t *testing.T) {
 
 
 func TestLastModifiedEmpty(t *testing.T) {
 func TestLastModifiedEmpty(t *testing.T) {
 
 
-	const screenName = "sn2day"
+	screenName := NewIdentScreenName("sn2day")
 
 
 	defer func() {
 	defer func() {
 		assert.NoError(t, os.Remove(testFile))
 		assert.NoError(t, os.Remove(testFile))
@@ -129,7 +129,7 @@ func TestLastModifiedEmpty(t *testing.T) {
 
 
 func TestLastModifiedNotEmpty(t *testing.T) {
 func TestLastModifiedNotEmpty(t *testing.T) {
 
 
-	const screenName = "sn2day"
+	screenName := NewIdentScreenName("sn2day")
 
 
 	defer func() {
 	defer func() {
 		assert.NoError(t, os.Remove(testFile))
 		assert.NoError(t, os.Remove(testFile))
@@ -159,7 +159,7 @@ func TestLastModifiedNotEmpty(t *testing.T) {
 
 
 func TestProfile(t *testing.T) {
 func TestProfile(t *testing.T) {
 
 
-	const screenName = "sn2day"
+	screenName := NewIdentScreenName("sn2day")
 
 
 	defer func() {
 	defer func() {
 		assert.NoError(t, os.Remove(testFile))
 		assert.NoError(t, os.Remove(testFile))
@@ -169,7 +169,7 @@ func TestProfile(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
 	u := User{
 	u := User{
-		ScreenName: screenName,
+		IdentScreenName: screenName,
 	}
 	}
 	if err := f.InsertUser(u); err != nil {
 	if err := f.InsertUser(u); err != nil {
 		t.Fatalf("failed to upsert new user: %s", err.Error())
 		t.Fatalf("failed to upsert new user: %s", err.Error())
@@ -215,7 +215,7 @@ func TestProfile(t *testing.T) {
 
 
 func TestProfileNonExistent(t *testing.T) {
 func TestProfileNonExistent(t *testing.T) {
 
 
-	const screenName = "sn2day"
+	screenName := NewIdentScreenName("sn2day")
 
 
 	defer func() {
 	defer func() {
 		assert.NoError(t, os.Remove(testFile))
 		assert.NoError(t, os.Remove(testFile))
@@ -242,12 +242,12 @@ func TestAdjacentUsers(t *testing.T) {
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
 
 
-	users, err := f.AdjacentUsers("userA")
+	users, err := f.AdjacentUsers(NewIdentScreenName("userA"))
 	if len(users) != 0 {
 	if len(users) != 0 {
 		t.Fatalf("expected no interested users, got %v", users)
 		t.Fatalf("expected no interested users, got %v", users)
 	}
 	}
 
 
-	users, err = f.AdjacentUsers("userB")
+	users, err = f.AdjacentUsers(NewIdentScreenName("userB"))
 	if len(users) != 0 {
 	if len(users) != 0 {
 		t.Fatalf("expected no interested users, got %v", users)
 		t.Fatalf("expected no interested users, got %v", users)
 	}
 	}
@@ -265,12 +265,12 @@ func TestUserStoreBuddiesBlockedUser(t *testing.T) {
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
 
 
-	users, err := f.Buddies("userA")
+	users, err := f.Buddies(NewIdentScreenName("userA"))
 	if len(users) != 0 {
 	if len(users) != 0 {
 		t.Fatalf("expected no buddies, got %v", users)
 		t.Fatalf("expected no buddies, got %v", users)
 	}
 	}
 
 
-	users, err = f.Buddies("userB")
+	users, err = f.Buddies(NewIdentScreenName("userB"))
 	if len(users) != 0 {
 	if len(users) != 0 {
 		t.Fatalf("expected no buddies, got %v", users)
 		t.Fatalf("expected no buddies, got %v", users)
 	}
 	}
@@ -285,12 +285,35 @@ func TestUserStoreBlockedA(t *testing.T) {
 	f, err := NewSQLiteUserStore(testFile)
 	f, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',0,13852,3,'userB',NULL,1691286176)`)
-	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
-	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
+	sn1 := NewIdentScreenName("userA")
+	sn2 := NewIdentScreenName("userB")
+
+	err = f.FeedbagUpsert(sn1, []wire.FeedbagItem{
+		{
+			GroupID: 0,
+			ItemID:  13852,
+			ClassID: 3,
+			Name:    "userB",
+		},
+		{
+			GroupID: 27631,
+			ItemID:  4016,
+			ClassID: 0,
+			Name:    "userB",
+		},
+	})
+	assert.NoError(t, err)
+
+	err = f.FeedbagUpsert(sn2, []wire.FeedbagItem{
+		{
+			GroupID: 28330,
+			ItemID:  8120,
+			ClassID: 0,
+			Name:    "userA",
+		},
+	})
+	assert.NoError(t, err)
 
 
-	sn1 := "userA"
-	sn2 := "userB"
 	blocked, err := f.BlockedState(sn1, sn2)
 	blocked, err := f.BlockedState(sn1, sn2)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("db err: %s", err.Error())
 		t.Fatalf("db err: %s", err.Error())
@@ -308,12 +331,35 @@ func TestUserStoreBlockedB(t *testing.T) {
 	f, err := NewSQLiteUserStore(testFile)
 	f, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',0,13852,3,'userA',NULL,1691286176)`)
-	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
-	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
+	sn1 := NewIdentScreenName("userA")
+	sn2 := NewIdentScreenName("userB")
+
+	err = f.FeedbagUpsert(sn1, []wire.FeedbagItem{
+		{
+			GroupID: 27631,
+			ItemID:  4016,
+			ClassID: 0,
+			Name:    "userB",
+		},
+	})
+	assert.NoError(t, err)
+
+	err = f.FeedbagUpsert(sn2, []wire.FeedbagItem{
+		{
+			GroupID: 0,
+			ItemID:  13852,
+			ClassID: 3,
+			Name:    "userA",
+		},
+		{
+			GroupID: 28330,
+			ItemID:  8120,
+			ClassID: 0,
+			Name:    "userA",
+		},
+	})
+	assert.NoError(t, err)
 
 
-	sn1 := "userA"
-	sn2 := "userB"
 	blocked, err := f.BlockedState(sn1, sn2)
 	blocked, err := f.BlockedState(sn1, sn2)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("db err: %s", err.Error())
 		t.Fatalf("db err: %s", err.Error())
@@ -334,8 +380,8 @@ func TestUserStoreBlockedNoBlocked(t *testing.T) {
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userA',27631,4016,0,'userB',NULL,1690508233)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
 	f.db.Exec(`INSERT INTO "feedbag" VALUES('userB',28330,8120,0,'userA',NULL,1691180328)`)
 
 
-	sn1 := "userA"
-	sn2 := "userB"
+	sn1 := NewIdentScreenName("userA")
+	sn2 := NewIdentScreenName("userB")
 	blocked, err := f.BlockedState(sn1, sn2)
 	blocked, err := f.BlockedState(sn1, sn2)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("db err: %s", err.Error())
 		t.Fatalf("db err: %s", err.Error())
@@ -353,24 +399,24 @@ func TestGetUser(t *testing.T) {
 	f, err := NewSQLiteUserStore(testFile)
 	f, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	expectUser := &User{
-		ScreenName:    "testscreenname",
-		AuthKey:       "theauthkey",
-		StrongMD5Pass: []byte("thepasshash"),
-	}
-	_, err = f.db.Exec(`INSERT INTO user (ScreenName, authKey, strongMD5Pass) VALUES(?, ?, ?)`,
-		expectUser.ScreenName, expectUser.AuthKey, expectUser.StrongMD5Pass)
-	if err != nil {
-		t.Fatalf("failed to insert user: %s", err.Error())
+	screenName := NewIdentScreenName("testscreenname")
+
+	insertedUser := &User{
+		IdentScreenName:   screenName,
+		DisplayScreenName: DisplayScreenName("testscreenname"),
+		AuthKey:           "theauthkey",
+		StrongMD5Pass:     []byte("thepasshash"),
 	}
 	}
+	err = f.InsertUser(*insertedUser)
+	assert.NoError(t, err)
 
 
-	actualUser, err := f.User(expectUser.ScreenName)
+	actualUser, err := f.User(screenName)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("failed to get user: %s", err.Error())
 		t.Fatalf("failed to get user: %s", err.Error())
 	}
 	}
 
 
-	if !reflect.DeepEqual(expectUser, actualUser) {
-		t.Fatalf("users are not equal. expect: %v actual: %v", expectUser, actualUser)
+	if !reflect.DeepEqual(insertedUser, actualUser) {
+		t.Fatalf("users are not equal. expect: %v actual: %v", insertedUser, actualUser)
 	}
 	}
 }
 }
 
 
@@ -382,7 +428,7 @@ func TestGetUserNotFound(t *testing.T) {
 	f, err := NewSQLiteUserStore(testFile)
 	f, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	actualUser, err := f.User("testscreenname")
+	actualUser, err := f.User(NewIdentScreenName("testscreenname"))
 	if err != nil {
 	if err != nil {
 		t.Fatalf("failed to get user: %s", err.Error())
 		t.Fatalf("failed to get user: %s", err.Error())
 	}
 	}
@@ -403,9 +449,18 @@ func TestSQLiteUserStore_Users(t *testing.T) {
 	}
 	}
 
 
 	want := []User{
 	want := []User{
-		{ScreenName: "userA"},
-		{ScreenName: "userB"},
-		{ScreenName: "userC"},
+		{
+			IdentScreenName:   NewIdentScreenName("userA"),
+			DisplayScreenName: "userA",
+		},
+		{
+			IdentScreenName:   NewIdentScreenName("userB"),
+			DisplayScreenName: "userB",
+		},
+		{
+			IdentScreenName:   NewIdentScreenName("userC"),
+			DisplayScreenName: "userC",
+		},
 	}
 	}
 
 
 	for _, u := range want {
 	for _, u := range want {
@@ -427,18 +482,27 @@ func TestSQLiteUserStore_DeleteUser_DeleteExistentUser(t *testing.T) {
 	f, err := NewSQLiteUserStore(testFile)
 	f, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	err = f.InsertUser(User{ScreenName: "userA"})
+	err = f.InsertUser(User{
+		IdentScreenName:   NewIdentScreenName("userA"),
+		DisplayScreenName: "userA",
+	})
 	assert.NoError(t, err)
 	assert.NoError(t, err)
-	err = f.InsertUser(User{ScreenName: "userB"})
+	err = f.InsertUser(User{
+		IdentScreenName:   NewIdentScreenName("userB"),
+		DisplayScreenName: "userB",
+	})
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	err = f.DeleteUser("userA")
+	err = f.DeleteUser(NewIdentScreenName("userA"))
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
 	have, err := f.AllUsers()
 	have, err := f.AllUsers()
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	want := []User{{ScreenName: "userB"}}
+	want := []User{{
+		IdentScreenName:   NewIdentScreenName("userB"),
+		DisplayScreenName: "userB",
+	}}
 	assert.Equal(t, want, have)
 	assert.Equal(t, want, have)
 }
 }
 
 
@@ -450,7 +514,7 @@ func TestSQLiteUserStore_DeleteUser_DeleteNonExistentUser(t *testing.T) {
 	f, err := NewSQLiteUserStore(testFile)
 	f, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	err = f.DeleteUser("userA")
+	err = f.DeleteUser(NewIdentScreenName("userA"))
 	assert.ErrorIs(t, ErrNoUser, err)
 	assert.ErrorIs(t, ErrNoUser, err)
 }
 }
 
 
@@ -462,21 +526,29 @@ func TestSQLiteUserStore_Buddies(t *testing.T) {
 	feedbagStore, err := NewSQLiteUserStore(testFile)
 	feedbagStore, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	assert.NoError(t, feedbagStore.FeedbagUpsert("userA", []wire.FeedbagItem{
-		{Name: "userB", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
-	}))
-	assert.NoError(t, feedbagStore.FeedbagUpsert("userB", []wire.FeedbagItem{
-		{Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
-	}))
-
-	want := []string{"userB", "userC", "userD"}
-	have, err := feedbagStore.Buddies("userA")
+	assert.NoError(t, feedbagStore.FeedbagUpsert(
+		NewIdentScreenName("userA"),
+		[]wire.FeedbagItem{
+			{Name: "userB", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
+		}))
+	assert.NoError(t, feedbagStore.FeedbagUpsert(
+		NewIdentScreenName("userB"),
+		[]wire.FeedbagItem{
+			{Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
+		}))
+
+	have, err := feedbagStore.Buddies(NewIdentScreenName("userA"))
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
+	want := []IdentScreenName{
+		NewIdentScreenName("userB"),
+		NewIdentScreenName("userC"),
+		NewIdentScreenName("userD"),
+	}
 	assert.Equal(t, want, have)
 	assert.Equal(t, want, have)
 }
 }
 
 
@@ -485,8 +557,9 @@ func TestNewStubUser(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
 	want := User{
 	want := User{
-		ScreenName: "userA",
-		AuthKey:    have.AuthKey,
+		IdentScreenName:   NewIdentScreenName("userA"),
+		DisplayScreenName: "userA",
+		AuthKey:           have.AuthKey,
 	}
 	}
 	assert.NoError(t, want.HashPassword("welcome1"))
 	assert.NoError(t, want.HashPassword("welcome1"))
 
 
@@ -501,24 +574,33 @@ func TestSQLiteUserStore_AdjacentUsers(t *testing.T) {
 	feedbagStore, err := NewSQLiteUserStore(testFile)
 	feedbagStore, err := NewSQLiteUserStore(testFile)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
-	assert.NoError(t, feedbagStore.FeedbagUpsert("userA", []wire.FeedbagItem{
-		{Name: "userB", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
-	}))
-	assert.NoError(t, feedbagStore.FeedbagUpsert("userB", []wire.FeedbagItem{
-		{Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
-	}))
-	assert.NoError(t, feedbagStore.FeedbagUpsert("userC", []wire.FeedbagItem{
-		{Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userB", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
-		{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
-	}))
-
-	want := []string{"userB", "userC"}
-	have, err := feedbagStore.AdjacentUsers("userA")
+	assert.NoError(t, feedbagStore.FeedbagUpsert(
+		NewIdentScreenName("userA"),
+		[]wire.FeedbagItem{
+			{Name: "userB", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
+		}))
+	assert.NoError(t, feedbagStore.FeedbagUpsert(
+		NewIdentScreenName("userB"),
+		[]wire.FeedbagItem{
+			{Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userC", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
+		}))
+	assert.NoError(t, feedbagStore.FeedbagUpsert(
+		NewIdentScreenName("userC"),
+		[]wire.FeedbagItem{
+			{Name: "userA", ItemID: 1, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userB", ItemID: 2, ClassID: wire.FeedbagClassIdBuddy},
+			{Name: "userD", ItemID: 3, ClassID: wire.FeedbagClassIdBuddy},
+		}))
+
+	want := []IdentScreenName{
+		NewIdentScreenName("userB"),
+		NewIdentScreenName("userC"),
+	}
+	have, err := feedbagStore.AdjacentUsers(NewIdentScreenName("userA"))
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
 	assert.Equal(t, want, have)
 	assert.Equal(t, want, have)
@@ -546,3 +628,57 @@ func TestSQLiteUserStore_BARTUpsertAndRetrieve(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	assert.Equal(t, item, b)
 	assert.Equal(t, item, b)
 }
 }
+
+func TestSQLiteUserStore_SetUserPassword_UserExists(t *testing.T) {
+	defer func() {
+		assert.NoError(t, os.Remove(testFile))
+	}()
+
+	feedbagStore, err := NewSQLiteUserStore(testFile)
+	assert.NoError(t, err)
+
+	u := User{
+		IdentScreenName:   NewIdentScreenName("theuser"),
+		DisplayScreenName: "theUser",
+	}
+	err = u.HashPassword("thepassword")
+	assert.NoError(t, err)
+
+	err = feedbagStore.InsertUser(u)
+	assert.NoError(t, err)
+
+	err = u.HashPassword("thenewpassword")
+	assert.NoError(t, err)
+
+	err = feedbagStore.SetUserPassword(u)
+	assert.NoError(t, err)
+
+	gotUser, err := feedbagStore.User(u.IdentScreenName)
+	assert.NoError(t, err)
+
+	valid := gotUser.ValidateHash(u.StrongMD5Pass)
+	assert.True(t, valid)
+}
+
+func TestSQLiteUserStore_SetUserPassword_ErrNoUser(t *testing.T) {
+	defer func() {
+		assert.NoError(t, os.Remove(testFile))
+	}()
+
+	feedbagStore, err := NewSQLiteUserStore(testFile)
+	assert.NoError(t, err)
+
+	u := User{
+		IdentScreenName:   NewIdentScreenName("theuser"),
+		DisplayScreenName: "theUser",
+	}
+	err = u.HashPassword("thepassword")
+	assert.NoError(t, err)
+
+	err = feedbagStore.SetUserPassword(u)
+	assert.ErrorIs(t, err, ErrNoUser)
+
+	// make sure previous transaction previously closed
+	err = feedbagStore.SetUserPassword(u)
+	assert.ErrorIs(t, err, ErrNoUser)
+}