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?

And if you don't have labels, adding them wouldn't break existing code.

For example you have this routine:

TEST
    write 1
    write 2
    write 3
    quit

It, when called would output

>do ^TEST
123

If you then add a label somewhere:

TEST
    write 1

MYLABEL
    write 2
    write 3
    quit

The routine would wok the same on previous calls:

>do ^TEST
123

But you'll also be able to call only the label:

>do MYLABEL^TEST
23