User requests or updates a self-subscription to a topic. Called as a result of {sub} or {meta set=sub}. Returns new access mode as *MsgAccessMode if user's access mode has changed, nil otherwise. sess - originating session pkt - client message which triggered this request; {sub} or {set} asUi
(sess *Session, pkt *ClientComMessage, asUid types.Uid, asChan bool, want string, private any)
| 1504 | // E. User is accepting ownership transfer (requesting ownership transfer is not permitted). |
| 1505 | // In case of a group topic the user may be a reader or a full subscriber. |
| 1506 | func (t *Topic) thisUserSub(sess *Session, pkt *ClientComMessage, asUid types.Uid, asChan bool, want string, |
| 1507 | private any) (*MsgAccessMode, error) { |
| 1508 | |
| 1509 | now := types.TimeNow() |
| 1510 | asLvl := auth.Level(pkt.AuthLvl) |
| 1511 | |
| 1512 | // Access mode values as they were before this request was processed. |
| 1513 | oldWant := types.ModeNone |
| 1514 | oldGiven := types.ModeNone |
| 1515 | |
| 1516 | // Parse access mode requested by the user |
| 1517 | modeWant := types.ModeUnset |
| 1518 | if want != "" { |
| 1519 | if err := modeWant.UnmarshalText([]byte(want)); err != nil { |
| 1520 | sess.queueOut(ErrMalformedReply(pkt, now)) |
| 1521 | return nil, err |
| 1522 | } |
| 1523 | } |
| 1524 | |
| 1525 | var err error |
| 1526 | // Check if it's an attempt at a new subscription to the topic / a first connection of a channel reader |
| 1527 | // (channel readers are not permanently cached). |
| 1528 | // It could be an actual subscription (IsJoiner() == true) or a ban (IsJoiner() == false). |
| 1529 | userData, existingSub := t.perUser[asUid] |
| 1530 | if !existingSub || userData.deleted { |
| 1531 | // New subscription or a not yet cached channel reader, either new or existing. |
| 1532 | |
| 1533 | // Check if the max number of subscriptions is already reached. |
| 1534 | if t.cat == types.TopicCatGrp && !asChan && t.subsCount() >= globals.maxSubscriberCount { |
| 1535 | sess.queueOut(ErrPolicyReply(pkt, now)) |
| 1536 | return nil, errors.New("max subscription count exceeded") |
| 1537 | } |
| 1538 | |
| 1539 | var sub *types.Subscription |
| 1540 | tname := t.name |
| 1541 | if t.cat == types.TopicCatP2P { |
| 1542 | // P2P could be here only if it was previously deleted. I.e. existingSub is always true for P2P. |
| 1543 | if modeWant != types.ModeUnset { |
| 1544 | userData.modeWant = modeWant |
| 1545 | } |
| 1546 | // If no modeWant is provided, leave existing one unchanged. |
| 1547 | |
| 1548 | // Make sure the user is not asking for unreasonable permissions |
| 1549 | userData.modeWant = (userData.modeWant & globals.typesModeCP2P) | types.ModeApprove |
| 1550 | } else if t.cat == types.TopicCatSys { |
| 1551 | if asLvl != auth.LevelRoot { |
| 1552 | sess.queueOut(ErrPermissionDeniedReply(pkt, now)) |
| 1553 | return nil, errors.New("subscription to 'sys' topic requires root access level") |
| 1554 | } |
| 1555 | |
| 1556 | // Assign default access levels |
| 1557 | userData.modeWant = types.ModeCSys |
| 1558 | userData.modeGiven = types.ModeCSys |
| 1559 | if modeWant != types.ModeUnset { |
| 1560 | userData.modeWant = (modeWant & types.ModeCSys) | types.ModeWrite | types.ModeJoin |
| 1561 | } |
| 1562 | } else if asChan { |
| 1563 | userData.isChan = true |
no test coverage detected