Nice feature to have.

One note about the code: if you have a BO that accepts only one type of messages, you can (I myself prefer to - as it immediately notifies the reader that this BO works with only one  type of messages, and not just a small BO in development) remove Message map altogether and define an OnRequest method, which would process these messages. Pull request.

If someone is interested, here's the same code but as a class:

/// Utility to match input against comma-separated string of masks.
Class util.Matcher
{

/// Returns $$$YES if input matches at least one element from the list
/// input - string to match
/// list - comma separated list of masks containig * and ?
/// write ##class(util.Matcher).MatchOr()
ClassMethod MatchOr(input As %String, list As %String) As %Boolean
{
    set ok = $$$NO
    for pie=1:1:$L(list,",") {
        set mask=$P(list,",",pie)
        if mask'="",..Match(input,mask) {
            set ok = $$$YES
        }
    }
    quit ok
}

/// Returns $$$YES if input matches all elements from the list
/// input - string to match
/// list - comma separated list of masks containig * and ?
/// write ##class(util.Matcher).MatchAnd()
ClassMethod MatchAnd(input As %String, list As %String) As %Boolean
{
    set ok = $$$YES
    for pie=1:1:$L(list,",") {
        set mask=$P(list,",",pie)
        if mask'="",'..Match(input,mask) {
            set ok = $$$NO
        }
    }
     quit ok
}

/// Returns $$$YES if input matches the mask
/// write ##class(util.Matcher).Match()
ClassMethod Match(input As %String, mask As %String) As %Boolean [ CodeMode = expression ]
{
input?@..MaskToPattern(mask)
}

/// Translate mask into a pattern
/// write ##class(util.Matcher).MaskToPattern()
ClassMethod MaskToPattern(mask As %String) As %String
{
    set pattern = ""
    set char = ""
    for pos = 1:1:$length(mask) {
        set curChar = $extract(mask, pos)
        if curChar = "*" {
            set pattern = pattern _ $select(char="":"", 1:"1"""_char_"""") _ ".E"
            set char = ""
        } elseif curChar = "?" {
            set pattern = pattern _ $select(char="":"", 1:"1"""_char_"""") _ "1E"
            set char = ""
        } else {
            set char = char _ curChar
        }
    }
    set pattern = pattern _ $select(char="":"", 1:"1"""_char_"""")
    quit pattern
}

}

Do not store passwords.

Store password hashes + Unique salt. When entered hash

Check $system.Encryption class for various hashing algorithms.

The only case where you need to store passwords is when they are used to authenticate Cache server against external systems.

In that case use the same $system.Encryption class to encrypt them for storage.

we're talking of 200-300+ passwords here.

Per user?