-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from jgknight/admin-service-formatsn
Add admin service, support screen name formatting
- Loading branch information
Showing
26 changed files
with
1,681 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
package foodgroup | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/mk6i/retro-aim-server/state" | ||
"github.com/mk6i/retro-aim-server/wire" | ||
) | ||
|
||
// NewAdminService creates an instance of AdminService. | ||
func NewAdminService( | ||
sessionManager SessionManager, | ||
accountManager AccountManager, | ||
buddyUpdateBroadcaster buddyBroadcaster, | ||
) *AdminService { | ||
return &AdminService{ | ||
sessionManager: sessionManager, | ||
accountManager: accountManager, | ||
buddyUpdateBroadcaster: buddyUpdateBroadcaster, | ||
} | ||
} | ||
|
||
// AdminService provides functionality for the Admin food group. | ||
// The Admin food group is used for client control of passwords, screen name formatting, | ||
// email address, and account confirmation. | ||
type AdminService struct { | ||
sessionManager SessionManager | ||
accountManager AccountManager | ||
buddyUpdateBroadcaster buddyBroadcaster | ||
} | ||
|
||
// ConfirmRequest returns the ScreenName account status. It returns SNAC | ||
// wire.AdminConfirmReply. The values in the return SNAC are | ||
// flag, URL, length | ||
func (s AdminService) ConfirmRequest(_ context.Context, frame wire.SNACFrame) (wire.SNACMessage, error) { | ||
return wire.SNACMessage{ | ||
Frame: wire.SNACFrame{ | ||
FoodGroup: wire.Admin, | ||
SubGroup: wire.AdminAcctConfirmReply, | ||
RequestID: frame.RequestID, | ||
}, | ||
Body: wire.SNAC_0x07_0x07_AdminConfirmReply{ | ||
Status: wire.AdminAcctConfirmStatusEmailSent, // todo: get from session/db | ||
}, | ||
}, nil | ||
} | ||
|
||
// InfoQuery returns the requested information about the account | ||
func (s AdminService) InfoQuery(_ context.Context, sess *state.Session, frame wire.SNACFrame, body wire.SNAC_0x07_0x02_AdminInfoQuery) (wire.SNACMessage, error) { | ||
var getAdminInfoReply = func(tag uint16, val any) wire.SNACMessage { | ||
return wire.SNACMessage{ | ||
Frame: wire.SNACFrame{ | ||
FoodGroup: wire.Admin, | ||
SubGroup: wire.AdminInfoReply, | ||
RequestID: frame.RequestID, | ||
}, | ||
Body: wire.SNAC_0x07_0x03_AdminInfoReply{ | ||
Permissions: wire.AdminInfoPermissionsReadWrite, // todo: what does this actually control? | ||
TLVBlock: wire.TLVBlock{ | ||
TLVList: wire.TLVList{ | ||
wire.NewTLV(tag, val), | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// wire.AdminTLVRegistrationStatus is used in the AIM Preferences > Privacy panel to control | ||
// Allow users who know my e-mail address to find... | ||
// o Nothing about me - wire.AdminInfoRegStatusNoDisclosure | ||
// o Only that I have an account - wire.AdminInfoRegStatusLimitDisclosure | ||
// o My screen name - wire.AdminInfoRegStatusFullDisclosure | ||
if _, hasRegStatus := body.TLVRestBlock.Slice(wire.AdminTLVRegistrationStatus); hasRegStatus { | ||
return getAdminInfoReply(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusFullDisclosure), nil // todo: get from session/db | ||
|
||
} else if _, hasEmail := body.TLVRestBlock.Slice(wire.AdminTLVEmailAddress); hasEmail { | ||
return getAdminInfoReply(wire.AdminTLVEmailAddress, sess.IdentScreenName().String()+"@aol.com"), nil // todo: get from session/db | ||
|
||
} else if _, hasNickName := body.TLVRestBlock.Slice(wire.AdminTLVScreenNameFormatted); hasNickName { | ||
return getAdminInfoReply(wire.AdminTLVScreenNameFormatted, sess.DisplayScreenName().String()), nil | ||
|
||
} | ||
|
||
return wire.SNACMessage{ | ||
Frame: wire.SNACFrame{ | ||
FoodGroup: wire.Admin, | ||
SubGroup: wire.AdminErr, | ||
RequestID: frame.RequestID, | ||
}, | ||
Body: wire.SNACError{ | ||
Code: wire.ErrorCodeNotSupportedByHost, | ||
}, | ||
}, nil | ||
} | ||
|
||
func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session, frame wire.SNACFrame, body wire.SNAC_0x07_0x04_AdminInfoChangeRequest) (wire.SNACMessage, error) { | ||
var replyMessage = func(tag uint16, val any) wire.SNACMessage { | ||
return wire.SNACMessage{ | ||
Frame: wire.SNACFrame{ | ||
FoodGroup: wire.Admin, | ||
SubGroup: wire.AdminInfoChangeReply, | ||
RequestID: frame.RequestID, | ||
}, | ||
Body: wire.SNAC_0x07_0x05_AdminChangeReply{ | ||
Permissions: wire.AdminInfoPermissionsReadWrite, | ||
TLVBlock: wire.TLVBlock{ | ||
TLVList: wire.TLVList{ | ||
wire.NewTLV(tag, val), | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
var validateProposedName = func(name state.DisplayScreenName) (ok bool, errorCode uint16) { | ||
if len(name) > 16 { | ||
// proposed name is too long | ||
// todo: 16 should be defined elsewhere | ||
return false, wire.AdminInfoErrorInvalidNickNameLength | ||
} else if name.IdentScreenName() != sess.IdentScreenName() { | ||
// proposed name does not match session name (e.g. malicious client) | ||
return false, wire.AdminInfoErrorInvalidNickName | ||
} | ||
return true, 0 | ||
} | ||
|
||
if sn, hasScreenNameFormatted := body.TLVRestBlock.Slice(wire.AdminTLVScreenNameFormatted); hasScreenNameFormatted { | ||
proposedName := state.DisplayScreenName(sn) | ||
if ok, errorCode := validateProposedName(proposedName); !ok { | ||
return wire.SNACMessage{ | ||
Frame: wire.SNACFrame{ | ||
FoodGroup: wire.Admin, | ||
SubGroup: wire.AdminErr, | ||
RequestID: frame.RequestID, | ||
}, | ||
Body: wire.SNACError{ | ||
Code: errorCode, | ||
}, | ||
}, nil | ||
} | ||
if err := s.accountManager.UpdateDisplayScreenName(proposedName); err != nil { | ||
return wire.SNACMessage{}, err | ||
} | ||
sess.SetDisplayScreenName(proposedName) | ||
if err := s.buddyUpdateBroadcaster.BroadcastBuddyArrived(ctx, sess); err != nil { | ||
return wire.SNACMessage{}, err | ||
} | ||
return replyMessage(wire.AdminTLVScreenNameFormatted, proposedName.String()), nil | ||
} | ||
return wire.SNACMessage{ | ||
Frame: wire.SNACFrame{ | ||
FoodGroup: wire.Admin, | ||
SubGroup: wire.AdminErr, | ||
RequestID: frame.RequestID, | ||
}, | ||
Body: wire.SNACError{ | ||
Code: wire.ErrorCodeNotSupportedByHost, | ||
}, | ||
}, nil | ||
} |
Oops, something went wrong.