Browse Source

remove draft/resume-0.5

tags/v2.7.0-rc1
Shivaram Lingamneni 2 years ago
parent
commit
ba21987d03
14 changed files with 4 additions and 683 deletions
  1. 0
    6
      gencapdefs.py
  2. 1
    6
      irc/caps/defs.go
  3. 0
    74
      irc/channel.go
  4. 3
    214
      irc/client.go
  5. 0
    20
      irc/client_lookup_set.go
  6. 0
    9
      irc/commands.go
  7. 0
    1
      irc/config.go
  8. 0
    30
      irc/getters.go
  9. 0
    58
      irc/handlers.go
  10. 0
    14
      irc/help.go
  11. 0
    133
      irc/idletimer.go
  12. 0
    6
      irc/numerics.go
  13. 0
    104
      irc/resume.go
  14. 0
    8
      irc/server.go

+ 0
- 6
gencapdefs.py View File

@@ -105,12 +105,6 @@ CAPDEFS = [
105 105
         url="https://ircv3.net/specs/extensions/channel-rename",
106 106
         standard="draft IRCv3",
107 107
     ),
108
-    CapDef(
109
-        identifier="Resume",
110
-        name="draft/resume-0.5",
111
-        url="https://github.com/DanielOaks/ircv3-specifications/blob/master+resume/extensions/resume.md",
112
-        standard="proposed IRCv3",
113
-    ),
114 108
     CapDef(
115 109
         identifier="SASL",
116 110
         name="sasl",

+ 1
- 6
irc/caps/defs.go View File

@@ -7,7 +7,7 @@ package caps
7 7
 
8 8
 const (
9 9
 	// number of recognized capabilities:
10
-	numCapabs = 28
10
+	numCapabs = 27
11 11
 	// length of the uint64 array that represents the bitset:
12 12
 	bitsetLen = 1
13 13
 )
@@ -65,10 +65,6 @@ const (
65 65
 	// https://github.com/ircv3/ircv3-specifications/pull/417
66 66
 	Relaymsg Capability = iota
67 67
 
68
-	// Resume is the proposed IRCv3 capability named "draft/resume-0.5":
69
-	// https://github.com/DanielOaks/ircv3-specifications/blob/master+resume/extensions/resume.md
70
-	Resume Capability = iota
71
-
72 68
 	// EchoMessage is the IRCv3 capability named "echo-message":
73 69
 	// https://ircv3.net/specs/extensions/echo-message-3.2.html
74 70
 	EchoMessage Capability = iota
@@ -142,7 +138,6 @@ var (
142 138
 		"draft/multiline",
143 139
 		"draft/register",
144 140
 		"draft/relaymsg",
145
-		"draft/resume-0.5",
146 141
 		"echo-message",
147 142
 		"extended-join",
148 143
 		"invite-notify",

+ 0
- 74
irc/channel.go View File

@@ -1035,80 +1035,6 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
1035 1035
 	client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname))
1036 1036
 }
1037 1037
 
1038
-// Resume is called after a successful global resume to:
1039
-// 1. Replace the old client with the new in the channel's data structures
1040
-// 2. Send JOIN and MODE lines to channel participants (including the new client)
1041
-// 3. Replay missed message history to the client
1042
-func (channel *Channel) Resume(session *Session, timestamp time.Time) {
1043
-	channel.resumeAndAnnounce(session)
1044
-	if !timestamp.IsZero() {
1045
-		channel.replayHistoryForResume(session, timestamp, time.Time{})
1046
-	}
1047
-}
1048
-
1049
-func (channel *Channel) resumeAndAnnounce(session *Session) {
1050
-	channel.stateMutex.RLock()
1051
-	memberData, found := channel.members[session.client]
1052
-	channel.stateMutex.RUnlock()
1053
-	if !found {
1054
-		return
1055
-	}
1056
-	oldModes := memberData.modes.String()
1057
-	if 0 < len(oldModes) {
1058
-		oldModes = "+" + oldModes
1059
-	}
1060
-
1061
-	// send join for old clients
1062
-	chname := channel.Name()
1063
-	details := session.client.Details()
1064
-	// TODO: for now, skip this entirely for auditoriums,
1065
-	// but really we should send it to voiced clients
1066
-	if !channel.flags.HasMode(modes.Auditorium) {
1067
-		for _, member := range channel.Members() {
1068
-			for _, mSes := range member.Sessions() {
1069
-				if mSes == session || mSes.capabilities.Has(caps.Resume) {
1070
-					continue
1071
-				}
1072
-
1073
-				if mSes.capabilities.Has(caps.ExtendedJoin) {
1074
-					mSes.Send(nil, details.nickMask, "JOIN", chname, details.accountName, details.realname)
1075
-				} else {
1076
-					mSes.Send(nil, details.nickMask, "JOIN", chname)
1077
-				}
1078
-
1079
-				if 0 < len(oldModes) {
1080
-					mSes.Send(nil, channel.server.name, "MODE", chname, oldModes, details.nick)
1081
-				}
1082
-			}
1083
-		}
1084
-	}
1085
-
1086
-	rb := NewResponseBuffer(session)
1087
-	// use blocking i/o to synchronize with the later history replay
1088
-	if rb.session.capabilities.Has(caps.ExtendedJoin) {
1089
-		rb.Add(nil, details.nickMask, "JOIN", channel.name, details.accountName, details.realname)
1090
-	} else {
1091
-		rb.Add(nil, details.nickMask, "JOIN", channel.name)
1092
-	}
1093
-	channel.SendTopic(session.client, rb, false)
1094
-	channel.Names(session.client, rb)
1095
-	rb.Send(true)
1096
-}
1097
-
1098
-func (channel *Channel) replayHistoryForResume(session *Session, after time.Time, before time.Time) {
1099
-	var items []history.Item
1100
-	afterS, beforeS := history.Selector{Time: after}, history.Selector{Time: before}
1101
-	_, seq, _ := channel.server.GetHistorySequence(channel, session.client, "")
1102
-	if seq != nil {
1103
-		items, _ = seq.Between(afterS, beforeS, channel.server.Config().History.ZNCMax)
1104
-	}
1105
-	rb := NewResponseBuffer(session)
1106
-	if len(items) != 0 {
1107
-		channel.replayHistoryItems(rb, items, false)
1108
-	}
1109
-	rb.Send(true)
1110
-}
1111
-
1112 1038
 func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, autoreplay bool) {
1113 1039
 	// send an empty batch if necessary, as per the CHATHISTORY spec
1114 1040
 	chname := channel.Name()

+ 3
- 214
irc/client.go View File

@@ -56,22 +56,11 @@ const (
56 56
 	// This is how long a client gets without sending any message, including the PONG to our
57 57
 	// PING, before we disconnect them:
58 58
 	DefaultTotalTimeout = 2*time.Minute + 30*time.Second
59
-	// Resumeable clients (clients who have negotiated caps.Resume) get longer:
60
-	ResumeableTotalTimeout = 3*time.Minute + 30*time.Second
61 59
 
62 60
 	// round off the ping interval by this much, see below:
63 61
 	PingCoalesceThreshold = time.Second
64 62
 )
65 63
 
66
-// ResumeDetails is a place to stash data at various stages of
67
-// the resume process: when handling the RESUME command itself,
68
-// when completing the registration, and when rejoining channels.
69
-type ResumeDetails struct {
70
-	PresentedToken    string
71
-	Timestamp         time.Time
72
-	HistoryIncomplete bool
73
-}
74
-
75 64
 // Client is an IRC client.
76 65
 type Client struct {
77 66
 	account            string
@@ -79,7 +68,6 @@ type Client struct {
79 68
 	accountRegDate     time.Time
80 69
 	accountSettings    AccountSettings
81 70
 	awayMessage        string
82
-	brbTimer           BrbTimer
83 71
 	channels           ChannelSet
84 72
 	ctime              time.Time
85 73
 	destroyed          bool
@@ -109,7 +97,6 @@ type Client struct {
109 97
 	registered         bool
110 98
 	registerCmdSent    bool // already sent the draft/register command, can't send it again
111 99
 	registrationTimer  *time.Timer
112
-	resumeID           string
113 100
 	server             *Server
114 101
 	skeleton           string
115 102
 	sessions           []*Session
@@ -164,7 +151,6 @@ type Session struct {
164 151
 
165 152
 	fakelag              Fakelag
166 153
 	deferredFakelagCount int
167
-	destroyed            uint32
168 154
 
169 155
 	certfp     string
170 156
 	peerCerts  []*x509.Certificate
@@ -184,8 +170,6 @@ type Session struct {
184 170
 
185 171
 	registrationMessages int
186 172
 
187
-	resumeID              string
188
-	resumeDetails         *ResumeDetails
189 173
 	zncPlaybackTimes      *zncPlaybackTimes
190 174
 	autoreplayMissedSince time.Time
191 175
 
@@ -259,20 +243,6 @@ func (s *Session) IP() net.IP {
259 243
 	return s.realIP
260 244
 }
261 245
 
262
-// returns whether the session was actively destroyed (for example, by ping
263
-// timeout or NS GHOST).
264
-// avoids a race condition between asynchronous idle-timing-out of sessions,
265
-// and a condition that allows implicit BRB on connection errors (since
266
-// destroy()'s socket.Close() appears to socket.Read() as a connection error)
267
-func (session *Session) Destroyed() bool {
268
-	return atomic.LoadUint32(&session.destroyed) == 1
269
-}
270
-
271
-// sets the timed-out flag
272
-func (session *Session) SetDestroyed() {
273
-	atomic.StoreUint32(&session.destroyed, 1)
274
-}
275
-
276 246
 // returns whether the client supports a smart history replay cap,
277 247
 // and therefore autoreplay-on-join and similar should be suppressed
278 248
 func (session *Session) HasHistoryCaps() bool {
@@ -371,7 +341,6 @@ func (server *Server) RunClient(conn IRCConn) {
371 341
 		client.requireSASLMessage = banMsg
372 342
 	}
373 343
 	client.history.Initialize(config.History.ClientLength, time.Duration(config.History.AutoresizeWindow))
374
-	client.brbTimer.Initialize(client)
375 344
 	session := &Session{
376 345
 		client:     client,
377 346
 		socket:     socket,
@@ -459,7 +428,6 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, channelToStatus m
459 428
 		client.SetMode(m, true)
460 429
 	}
461 430
 	client.history.Initialize(0, 0)
462
-	client.brbTimer.Initialize(client)
463 431
 
464 432
 	server.accounts.Login(client, account)
465 433
 
@@ -553,7 +521,7 @@ func (client *Client) lookupHostname(session *Session, overwrite bool) {
553 521
 	cloakedHostname := config.Server.Cloaks.ComputeCloak(ip)
554 522
 	client.stateMutex.Lock()
555 523
 	defer client.stateMutex.Unlock()
556
-	// update the hostname if this is a new connection or a resume, but not if it's a reattach
524
+	// update the hostname if this is a new connection, but not if it's a reattach
557 525
 	if overwrite || client.rawHostname == "" {
558 526
 		client.rawHostname = hostname
559 527
 		client.cloakedHostname = cloakedHostname
@@ -671,14 +639,7 @@ func (client *Client) run(session *Session) {
671 639
 	isReattach := client.Registered()
672 640
 	if isReattach {
673 641
 		client.Touch(session)
674
-		if session.resumeDetails != nil {
675
-			session.playResume()
676
-			session.resumeDetails = nil
677
-			client.brbTimer.Disable()
678
-			session.SetAway("") // clear BRB message if any
679
-		} else {
680
-			client.playReattachMessages(session)
681
-		}
642
+		client.playReattachMessages(session)
682 643
 	}
683 644
 
684 645
 	firstLine := !isReattach
@@ -697,11 +658,6 @@ func (client *Client) run(session *Session) {
697 658
 				quitMessage = "connection closed"
698 659
 			}
699 660
 			client.Quit(quitMessage, session)
700
-			// since the client did not actually send us a QUIT,
701
-			// give them a chance to resume if applicable:
702
-			if !session.Destroyed() {
703
-				client.brbTimer.Enable()
704
-			}
705 661
 			break
706 662
 		}
707 663
 
@@ -852,9 +808,6 @@ func (client *Client) updateIdleTimer(session *Session, now time.Time) {
852 808
 
853 809
 func (session *Session) handleIdleTimeout() {
854 810
 	totalTimeout := DefaultTotalTimeout
855
-	if session.capabilities.Has(caps.Resume) {
856
-		totalTimeout = ResumeableTotalTimeout
857
-	}
858 811
 	pingTimeout := DefaultIdleTimeout
859 812
 	if session.isTor {
860 813
 		pingTimeout = TorIdleTimeout
@@ -911,151 +864,6 @@ func (session *Session) Ping() {
911 864
 	session.Send(nil, "", "PING", session.client.Nick())
912 865
 }
913 866
 
914
-// tryResume tries to resume if the client asked us to.
915
-func (session *Session) tryResume() (success bool) {
916
-	var oldResumeID string
917
-
918
-	defer func() {
919
-		if success {
920
-			// "On a successful request, the server [...] terminates the old client's connection"
921
-			oldSession := session.client.GetSessionByResumeID(oldResumeID)
922
-			if oldSession != nil {
923
-				session.client.destroy(oldSession)
924
-			}
925
-		} else {
926
-			session.resumeDetails = nil
927
-		}
928
-	}()
929
-
930
-	client := session.client
931
-	server := client.server
932
-	config := server.Config()
933
-
934
-	oldClient, oldResumeID := server.resumeManager.VerifyToken(client, session.resumeDetails.PresentedToken)
935
-	if oldClient == nil {
936
-		session.Send(nil, server.name, "FAIL", "RESUME", "INVALID_TOKEN", client.t("Cannot resume connection, token is not valid"))
937
-		return
938
-	}
939
-
940
-	resumeAllowed := config.Server.AllowPlaintextResume || (oldClient.HasMode(modes.TLS) && client.HasMode(modes.TLS))
941
-	if !resumeAllowed {
942
-		session.Send(nil, server.name, "FAIL", "RESUME", "INSECURE_SESSION", client.t("Cannot resume connection, old and new clients must have TLS"))
943
-		return
944
-	}
945
-
946
-	err := server.clients.Resume(oldClient, session)
947
-	if err != nil {
948
-		session.Send(nil, server.name, "FAIL", "RESUME", "CANNOT_RESUME", client.t("Cannot resume connection"))
949
-		return
950
-	}
951
-
952
-	success = true
953
-	client.server.logger.Debug("quit", fmt.Sprintf("%s is being resumed", oldClient.Nick()))
954
-
955
-	return
956
-}
957
-
958
-// playResume is called from the session's fresh goroutine after a resume;
959
-// it sends notifications to friends, then plays the registration burst and replays
960
-// stored history to the session
961
-func (session *Session) playResume() {
962
-	client := session.client
963
-	server := client.server
964
-	config := server.Config()
965
-
966
-	friends := make(ClientSet)
967
-	var oldestLostMessage time.Time
968
-
969
-	// work out how much time, if any, is not covered by history buffers
970
-	// assume that a persistent buffer covers the whole resume period
971
-	for _, channel := range client.Channels() {
972
-		for _, member := range channel.auditoriumFriends(client) {
973
-			friends.Add(member)
974
-		}
975
-		status, _, _ := channel.historyStatus(config)
976
-		if status == HistoryEphemeral {
977
-			lastDiscarded := channel.history.LastDiscarded()
978
-			if oldestLostMessage.Before(lastDiscarded) {
979
-				oldestLostMessage = lastDiscarded
980
-			}
981
-		}
982
-	}
983
-	cHistoryStatus, _ := client.historyStatus(config)
984
-	if cHistoryStatus == HistoryEphemeral {
985
-		lastDiscarded := client.history.LastDiscarded()
986
-		if oldestLostMessage.Before(lastDiscarded) {
987
-			oldestLostMessage = lastDiscarded
988
-		}
989
-	}
990
-
991
-	timestamp := session.resumeDetails.Timestamp
992
-	gap := oldestLostMessage.Sub(timestamp)
993
-	session.resumeDetails.HistoryIncomplete = gap > 0 || timestamp.IsZero()
994
-	gapSeconds := int(gap.Seconds()) + 1 // round up to avoid confusion
995
-
996
-	details := client.Details()
997
-	oldNickmask := details.nickMask
998
-	client.lookupHostname(session, true)
999
-	hostname := client.Hostname() // may be a vhost
1000
-	timestampString := timestamp.Format(IRCv3TimestampFormat)
1001
-
1002
-	// send quit/resume messages to friends
1003
-	for friend := range friends {
1004
-		if friend == client {
1005
-			continue
1006
-		}
1007
-		for _, fSession := range friend.Sessions() {
1008
-			if fSession.capabilities.Has(caps.Resume) {
1009
-				if !session.resumeDetails.HistoryIncomplete {
1010
-					fSession.Send(nil, oldNickmask, "RESUMED", hostname, "ok")
1011
-				} else if session.resumeDetails.HistoryIncomplete && !timestamp.IsZero() {
1012
-					fSession.Send(nil, oldNickmask, "RESUMED", hostname, timestampString)
1013
-				} else {
1014
-					fSession.Send(nil, oldNickmask, "RESUMED", hostname)
1015
-				}
1016
-			} else {
1017
-				if !session.resumeDetails.HistoryIncomplete {
1018
-					fSession.Send(nil, oldNickmask, "QUIT", friend.t("Client reconnected"))
1019
-				} else if session.resumeDetails.HistoryIncomplete && !timestamp.IsZero() {
1020
-					fSession.Send(nil, oldNickmask, "QUIT", fmt.Sprintf(friend.t("Client reconnected (up to %d seconds of message history lost)"), gapSeconds))
1021
-				} else {
1022
-					fSession.Send(nil, oldNickmask, "QUIT", friend.t("Client reconnected (message history may have been lost)"))
1023
-				}
1024
-			}
1025
-		}
1026
-	}
1027
-
1028
-	if session.resumeDetails.HistoryIncomplete {
1029
-		if !timestamp.IsZero() {
1030
-			session.Send(nil, client.server.name, "WARN", "RESUME", "HISTORY_LOST", fmt.Sprintf(client.t("Resume may have lost up to %d seconds of history"), gapSeconds))
1031
-		} else {
1032
-			session.Send(nil, client.server.name, "WARN", "RESUME", "HISTORY_LOST", client.t("Resume may have lost some message history"))
1033
-		}
1034
-	}
1035
-
1036
-	session.Send(nil, client.server.name, "RESUME", "SUCCESS", details.nick)
1037
-
1038
-	server.playRegistrationBurst(session)
1039
-
1040
-	for _, channel := range client.Channels() {
1041
-		channel.Resume(session, timestamp)
1042
-	}
1043
-
1044
-	// replay direct PRIVSMG history
1045
-	_, privmsgSeq, err := server.GetHistorySequence(nil, client, "")
1046
-	if !timestamp.IsZero() && err == nil && privmsgSeq != nil {
1047
-		after := history.Selector{Time: timestamp}
1048
-		items, _ := privmsgSeq.Between(after, history.Selector{}, config.History.ZNCMax)
1049
-		if len(items) != 0 {
1050
-			rb := NewResponseBuffer(session)
1051
-			client.replayPrivmsgHistory(rb, items, "")
1052
-			rb.Send(true)
1053
-		}
1054
-	}
1055
-
1056
-	session.resumeDetails = nil
1057
-}
1058
-
1059 867
 func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string) {
1060 868
 	var batchID string
1061 869
 	details := client.Details()
@@ -1388,8 +1196,6 @@ func (client *Client) destroy(session *Session) {
1388 1196
 	client.stateMutex.Lock()
1389 1197
 
1390 1198
 	details := client.detailsNoMutex()
1391
-	brbState := client.brbTimer.state
1392
-	brbAt := client.brbTimer.brbAt
1393 1199
 	wasReattach := session != nil && session.client != client
1394 1200
 	sessionRemoved := false
1395 1201
 	registered := client.registered
@@ -1431,9 +1237,7 @@ func (client *Client) destroy(session *Session) {
1431 1237
 	}
1432 1238
 
1433 1239
 	// should we destroy the whole client this time?
1434
-	// BRB is not respected if this is a destroy of the whole client (i.e., session == nil)
1435
-	brbEligible := session != nil && brbState == BrbEnabled
1436
-	shouldDestroy := !client.destroyed && remainingSessions == 0 && !brbEligible && !alwaysOn
1240
+	shouldDestroy := !client.destroyed && remainingSessions == 0 && !alwaysOn
1437 1241
 	// decrement stats on a true destroy, or for the removal of the last connected session
1438 1242
 	// of an always-on client
1439 1243
 	shouldDecrement := shouldDestroy || (alwaysOn && len(sessionsToDestroy) != 0 && len(client.sessions) == 0)
@@ -1479,7 +1283,6 @@ func (client *Client) destroy(session *Session) {
1479 1283
 		// send quit/error message to client if they haven't been sent already
1480 1284
 		client.Quit("", session)
1481 1285
 		quitMessage = session.quitMessage // doesn't need synch, we already detached
1482
-		session.SetDestroyed()
1483 1286
 		session.socket.Close()
1484 1287
 
1485 1288
 		// clean up monitor state
@@ -1538,8 +1341,6 @@ func (client *Client) destroy(session *Session) {
1538 1341
 		client.server.whoWas.Append(client.WhoWas())
1539 1342
 	}
1540 1343
 
1541
-	client.server.resumeManager.Delete(client)
1542
-
1543 1344
 	// alert monitors
1544 1345
 	if registered {
1545 1346
 		client.server.monitorManager.AlertAbout(details.nick, details.nickCasefolded, false)
@@ -1561,20 +1362,8 @@ func (client *Client) destroy(session *Session) {
1561 1362
 	client.server.clients.Remove(client)
1562 1363
 
1563 1364
 	// clean up self
1564
-	client.brbTimer.Disable()
1565
-
1566 1365
 	client.server.accounts.Logout(client)
1567 1366
 
1568
-	// this happens under failure to return from BRB
1569
-	if quitMessage == "" {
1570
-		if brbState == BrbDead && !brbAt.IsZero() {
1571
-			awayMessage := client.AwayMessage()
1572
-			if awayMessage == "" {
1573
-				awayMessage = "Disconnected" // auto-BRB
1574
-			}
1575
-			quitMessage = fmt.Sprintf("%s [%s ago]", awayMessage, time.Since(brbAt).Truncate(time.Second).String())
1576
-		}
1577
-	}
1578 1367
 	if quitMessage == "" {
1579 1368
 		quitMessage = "Exited"
1580 1369
 	}

+ 0
- 20
irc/client_lookup_set.go View File

@@ -81,26 +81,6 @@ func (clients *ClientManager) Remove(client *Client) error {
81 81
 	return clients.removeInternal(client, oldcfnick, oldskeleton)
82 82
 }
83 83
 
84
-// Handles a RESUME by attaching a session to a designated client. It is the
85
-// caller's responsibility to verify that the resume is allowed (checking tokens,
86
-// TLS status, etc.) before calling this.
87
-func (clients *ClientManager) Resume(oldClient *Client, session *Session) (err error) {
88
-	clients.Lock()
89
-	defer clients.Unlock()
90
-
91
-	cfnick := oldClient.NickCasefolded()
92
-	if _, ok := clients.byNick[cfnick]; !ok {
93
-		return errNickMissing
94
-	}
95
-
96
-	success, _, _, _ := oldClient.AddSession(session)
97
-	if !success {
98
-		return errNickMissing
99
-	}
100
-
101
-	return nil
102
-}
103
-
104 84
 // SetNick sets a client's nickname, validating it against nicknames in use
105 85
 // XXX: dryRun validates a client's ability to claim a nick, without
106 86
 // actually claiming it

+ 0
- 9
irc/commands.go View File

@@ -93,10 +93,6 @@ func init() {
93 93
 			minParams:      1,
94 94
 			allowedInBatch: true,
95 95
 		},
96
-		"BRB": {
97
-			handler:   brbHandler,
98
-			minParams: 0,
99
-		},
100 96
 		"CAP": {
101 97
 			handler:      capHandler,
102 98
 			usablePreReg: true,
@@ -257,11 +253,6 @@ func init() {
257 253
 			handler:   renameHandler,
258 254
 			minParams: 2,
259 255
 		},
260
-		"RESUME": {
261
-			handler:      resumeHandler,
262
-			usablePreReg: true,
263
-			minParams:    1,
264
-		},
265 256
 		"SAJOIN": {
266 257
 			handler:   sajoinHandler,
267 258
 			minParams: 1,

+ 0
- 1
irc/config.go View File

@@ -570,7 +570,6 @@ type Config struct {
570 570
 		WebIRC               []webircConfig `yaml:"webirc"`
571 571
 		MaxSendQString       string         `yaml:"max-sendq"`
572 572
 		MaxSendQBytes        int
573
-		AllowPlaintextResume bool `yaml:"allow-plaintext-resume"`
574 573
 		Compatibility        struct {
575 574
 			ForceTrailing      *bool `yaml:"force-trailing"`
576 575
 			forceTrailing      bool

+ 0
- 30
irc/getters.go View File

@@ -54,18 +54,6 @@ func (client *Client) Sessions() (sessions []*Session) {
54 54
 	return
55 55
 }
56 56
 
57
-func (client *Client) GetSessionByResumeID(resumeID string) (result *Session) {
58
-	client.stateMutex.RLock()
59
-	defer client.stateMutex.RUnlock()
60
-
61
-	for _, session := range client.sessions {
62
-		if session.resumeID == resumeID {
63
-			return session
64
-		}
65
-	}
66
-	return
67
-}
68
-
69 57
 type SessionData struct {
70 58
 	ctime     time.Time
71 59
 	atime     time.Time
@@ -157,12 +145,6 @@ func (client *Client) removeSession(session *Session) (success bool, length int)
157 145
 	return
158 146
 }
159 147
 
160
-func (session *Session) SetResumeID(resumeID string) {
161
-	session.client.stateMutex.Lock()
162
-	session.resumeID = resumeID
163
-	session.client.stateMutex.Unlock()
164
-}
165
-
166 148
 func (client *Client) Nick() string {
167 149
 	client.stateMutex.RLock()
168 150
 	defer client.stateMutex.RUnlock()
@@ -265,18 +247,6 @@ func (client *Client) uniqueIdentifiers() (nickCasefolded string, skeleton strin
265 247
 	return client.nickCasefolded, client.skeleton
266 248
 }
267 249
 
268
-func (client *Client) ResumeID() string {
269
-	client.stateMutex.RLock()
270
-	defer client.stateMutex.RUnlock()
271
-	return client.resumeID
272
-}
273
-
274
-func (client *Client) SetResumeID(id string) {
275
-	client.stateMutex.Lock()
276
-	defer client.stateMutex.Unlock()
277
-	client.resumeID = id
278
-}
279
-
280 250
 func (client *Client) Oper() *Oper {
281 251
 	client.stateMutex.RLock()
282 252
 	defer client.stateMutex.RUnlock()

+ 0
- 58
irc/handlers.go View File

@@ -420,31 +420,6 @@ func batchHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon
420 420
 	return false
421 421
 }
422 422
 
423
-// BRB [message]
424
-func brbHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
425
-	success, duration := client.brbTimer.Enable()
426
-	if !success {
427
-		rb.Add(nil, server.name, "FAIL", "BRB", "CANNOT_BRB", client.t("Your client does not support BRB"))
428
-		return false
429
-	} else {
430
-		rb.Add(nil, server.name, "BRB", strconv.Itoa(int(duration.Seconds())))
431
-	}
432
-
433
-	var message string
434
-	if 0 < len(msg.Params) {
435
-		message = msg.Params[0]
436
-	} else {
437
-		message = client.t("I'll be right back")
438
-	}
439
-
440
-	if len(client.Sessions()) == 1 {
441
-		// true BRB
442
-		rb.session.SetAway(message)
443
-	}
444
-
445
-	return true
446
-}
447
-
448 423
 // CAP <subcmd> [<caps>]
449 424
 func capHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
450 425
 	details := client.Details()
@@ -540,15 +515,6 @@ func capHandler(server *Server, client *Client, msg ircmsg.Message, rb *Response
540 515
 		rb.session.capabilities.Subtract(toRemove)
541 516
 		rb.Add(nil, server.name, "CAP", details.nick, "ACK", capString)
542 517
 
543
-		// if this is the first time the client is requesting a resume token,
544
-		// send it to them
545
-		if toAdd.Has(caps.Resume) {
546
-			token, id := server.resumeManager.GenerateToken(client)
547
-			if token != "" {
548
-				rb.Add(nil, server.name, "RESUME", "TOKEN", token)
549
-				rb.session.SetResumeID(id)
550
-			}
551
-		}
552 518
 	case "END":
553 519
 		if !client.registered {
554 520
 			rb.session.capState = caps.NegotiatedState
@@ -2809,30 +2775,6 @@ func renameHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
2809 2775
 	return false
2810 2776
 }
2811 2777
 
2812
-// RESUME <token> [timestamp]
2813
-func resumeHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
2814
-	details := ResumeDetails{
2815
-		PresentedToken: msg.Params[0],
2816
-	}
2817
-
2818
-	if client.registered {
2819
-		rb.Add(nil, server.name, "FAIL", "RESUME", "REGISTRATION_IS_COMPLETED", client.t("Cannot resume connection, connection registration has already been completed"))
2820
-		return false
2821
-	}
2822
-
2823
-	if 1 < len(msg.Params) {
2824
-		ts, err := time.Parse(IRCv3TimestampFormat, msg.Params[1])
2825
-		if err == nil {
2826
-			details.Timestamp = ts
2827
-		} else {
2828
-			rb.Add(nil, server.name, "WARN", "RESUME", "HISTORY_LOST", client.t("Timestamp is not in 2006-01-02T15:04:05.999Z format, ignoring it"))
2829
-		}
2830
-	}
2831
-
2832
-	rb.session.resumeDetails = &details
2833
-	return false
2834
-}
2835
-
2836 2778
 // SANICK <oldnick> <nickname>
2837 2779
 func sanickHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
2838 2780
 	targetNick := msg.Params[0]

+ 0
- 14
irc/help.go View File

@@ -129,14 +129,6 @@ longer away.`,
129 129
 
130 130
 BATCH initiates an IRCv3 client-to-server batch. You should never need to
131 131
 issue this command manually.`,
132
-	},
133
-	"brb": {
134
-		text: `BRB [message]
135
-
136
-Disconnects you from the server, while instructing the server to keep you
137
-present for a short time window. During this window, you can either resume
138
-or reattach to your nickname. If [message] is sent, it is used as your away
139
-message (and as your quit message if you don't return in time).`,
140 132
 	},
141 133
 	"cap": {
142 134
 		text: `CAP <subcommand> [:<capabilities>]
@@ -495,12 +487,6 @@ Registers an account in accordance with the draft/register capability.`,
495 487
 		text: `REHASH
496 488
 
497 489
 Reloads the config file and updates TLS certificates on listeners`,
498
-	},
499
-	"resume": {
500
-		text: `RESUME <oldnick> [timestamp]
501
-
502
-Sent before registration has completed, this indicates that the client wants to
503
-resume their old connection <oldnick>.`,
504 490
 	},
505 491
 	"time": {
506 492
 		text: `TIME [server]

+ 0
- 133
irc/idletimer.go View File

@@ -1,133 +0,0 @@
1
-// Copyright (c) 2017 Shivaram Lingamneni <slingamn@cs.stanford.edu>
2
-// released under the MIT license
3
-
4
-package irc
5
-
6
-import (
7
-	"time"
8
-)
9
-
10
-// BrbTimer is a timer on the client as a whole (not an individual session) for implementing
11
-// the BRB command and related functionality (where a client can remain online without
12
-// having any connected sessions).
13
-
14
-type BrbState uint
15
-
16
-const (
17
-	// BrbDisabled is the default state; the client will be disconnected if it has no sessions
18
-	BrbDisabled BrbState = iota
19
-	// BrbEnabled allows the client to remain online without sessions; if a timeout is
20
-	// reached, it will be removed
21
-	BrbEnabled
22
-	// BrbDead is the state of a client after its timeout has expired; it will be removed
23
-	// and therefore new sessions cannot be attached to it
24
-	BrbDead
25
-)
26
-
27
-type BrbTimer struct {
28
-	// XXX we use client.stateMutex for synchronization, so we can atomically test
29
-	// conditions that use both brbTimer.state and client.sessions. This code
30
-	// is tightly coupled with the rest of Client.
31
-	client *Client
32
-
33
-	state    BrbState
34
-	brbAt    time.Time
35
-	duration time.Duration
36
-	timer    *time.Timer
37
-}
38
-
39
-func (bt *BrbTimer) Initialize(client *Client) {
40
-	bt.client = client
41
-}
42
-
43
-// attempts to enable BRB for a client, returns whether it succeeded
44
-func (bt *BrbTimer) Enable() (success bool, duration time.Duration) {
45
-	// TODO make this configurable
46
-	duration = ResumeableTotalTimeout
47
-
48
-	bt.client.stateMutex.Lock()
49
-	defer bt.client.stateMutex.Unlock()
50
-
51
-	if !bt.client.registered || bt.client.alwaysOn || bt.client.resumeID == "" {
52
-		return
53
-	}
54
-
55
-	switch bt.state {
56
-	case BrbDisabled, BrbEnabled:
57
-		bt.state = BrbEnabled
58
-		bt.duration = duration
59
-		bt.resetTimeout()
60
-		// only track the earliest BRB, if multiple sessions are BRB'ing at once
61
-		// TODO(#524) this is inaccurate in case of an auto-BRB
62
-		if bt.brbAt.IsZero() {
63
-			bt.brbAt = time.Now().UTC()
64
-		}
65
-		success = true
66
-	default:
67
-		// BrbDead
68
-		success = false
69
-	}
70
-	return
71
-}
72
-
73
-// turns off BRB for a client and stops the timer; used on resume and during
74
-// client teardown
75
-func (bt *BrbTimer) Disable() (brbAt time.Time) {
76
-	bt.client.stateMutex.Lock()
77
-	defer bt.client.stateMutex.Unlock()
78
-
79
-	if bt.state == BrbEnabled {
80
-		bt.state = BrbDisabled
81
-		brbAt = bt.brbAt
82
-		bt.brbAt = time.Time{}
83
-	}
84
-	bt.resetTimeout()
85
-	return
86
-}
87
-
88
-func (bt *BrbTimer) resetTimeout() {
89
-	if bt.timer != nil {
90
-		bt.timer.Stop()
91
-	}
92
-	if bt.state != BrbEnabled {
93
-		return
94
-	}
95
-	if bt.timer == nil {
96
-		bt.timer = time.AfterFunc(bt.duration, bt.processTimeout)
97
-	} else {
98
-		bt.timer.Reset(bt.duration)
99
-	}
100
-}
101
-
102
-func (bt *BrbTimer) processTimeout() {
103
-	dead := false
104
-	defer func() {
105
-		if dead {
106
-			bt.client.Quit(bt.client.AwayMessage(), nil)
107
-			bt.client.destroy(nil)
108
-		}
109
-	}()
110
-
111
-	bt.client.stateMutex.Lock()
112
-	defer bt.client.stateMutex.Unlock()
113
-
114
-	if bt.client.alwaysOn {
115
-		return
116
-	}
117
-
118
-	switch bt.state {
119
-	case BrbDisabled, BrbEnabled:
120
-		if len(bt.client.sessions) == 0 {
121
-			// client never returned, quit them
122
-			bt.state = BrbDead
123
-			dead = true
124
-		} else {
125
-			// client resumed, reattached, or has another active session
126
-			bt.state = BrbDisabled
127
-			bt.brbAt = time.Time{}
128
-		}
129
-	case BrbDead:
130
-		dead = true // shouldn't be possible but whatever
131
-	}
132
-	bt.resetTimeout()
133
-}

+ 0
- 6
irc/numerics.go View File

@@ -196,10 +196,4 @@ const (
196 196
 	RPL_REG_VERIFICATION_REQUIRED = "927"
197 197
 	ERR_TOOMANYLANGUAGES          = "981"
198 198
 	ERR_NOLANGUAGE                = "982"
199
-
200
-	// draft numerics
201
-	// these haven't been assigned actual codes, so we use RPL_NONE's code (300),
202
-	// since RPL_NONE is intended to be used when testing / debugging / etc features.
203
-
204
-	ERR_CANNOT_RESUME = "300"
205 199
 )

+ 0
- 104
irc/resume.go View File

@@ -1,104 +0,0 @@
1
-// Copyright (c) 2019 Shivaram Lingamneni <slingamn@cs.stanford.edu>
2
-// released under the MIT license
3
-
4
-package irc
5
-
6
-import (
7
-	"sync"
8
-
9
-	"github.com/oragono/oragono/irc/utils"
10
-)
11
-
12
-// implements draft/resume, in particular the issuing, management, and verification
13
-// of resume tokens with two components: a unique ID and a secret key
14
-
15
-type resumeTokenPair struct {
16
-	client *Client
17
-	secret string
18
-}
19
-
20
-type ResumeManager struct {
21
-	sync.Mutex // level 2
22
-
23
-	resumeIDtoCreds map[string]resumeTokenPair
24
-	server          *Server
25
-}
26
-
27
-func (rm *ResumeManager) Initialize(server *Server) {
28
-	rm.resumeIDtoCreds = make(map[string]resumeTokenPair)
29
-	rm.server = server
30
-}
31
-
32
-// GenerateToken generates a resume token for a client. If the client has
33
-// already been assigned one, it returns "".
34
-func (rm *ResumeManager) GenerateToken(client *Client) (token string, id string) {
35
-	id = utils.GenerateSecretToken()
36
-	secret := utils.GenerateSecretToken()
37
-
38
-	rm.Lock()
39
-	defer rm.Unlock()
40
-
41
-	if client.ResumeID() != "" {
42
-		return
43
-	}
44
-
45
-	client.SetResumeID(id)
46
-	rm.resumeIDtoCreds[id] = resumeTokenPair{
47
-		client: client,
48
-		secret: secret,
49
-	}
50
-
51
-	return id + secret, id
52
-}
53
-
54
-// VerifyToken looks up the client corresponding to a resume token, returning
55
-// nil if there is no such client or the token is invalid. If successful,
56
-// the token is consumed and cannot be used to resume again.
57
-func (rm *ResumeManager) VerifyToken(newClient *Client, token string) (oldClient *Client, id string) {
58
-	if len(token) != 2*utils.SecretTokenLength {
59
-		return
60
-	}
61
-
62
-	rm.Lock()
63
-	defer rm.Unlock()
64
-
65
-	id = token[:utils.SecretTokenLength]
66
-	pair, ok := rm.resumeIDtoCreds[id]
67
-	if !ok {
68
-		return
69
-	}
70
-	// disallow resume of an unregistered client; this prevents the use of
71
-	// resume as an auth bypass
72
-	if !pair.client.Registered() {
73
-		return
74
-	}
75
-
76
-	if utils.SecretTokensMatch(pair.secret, token[utils.SecretTokenLength:]) {
77
-		oldClient = pair.client // success!
78
-		// consume the token, ensuring that at most one resume can succeed
79
-		delete(rm.resumeIDtoCreds, id)
80
-		// old client is henceforth resumeable under new client's creds (possibly empty)
81
-		newResumeID := newClient.ResumeID()
82
-		oldClient.SetResumeID(newResumeID)
83
-		if newResumeID != "" {
84
-			if newResumeCreds, ok := rm.resumeIDtoCreds[newResumeID]; ok {
85
-				newResumeCreds.client = oldClient
86
-				rm.resumeIDtoCreds[newResumeID] = newResumeCreds
87
-			}
88
-		}
89
-		// new client no longer "owns" newResumeID, remove the association
90
-		newClient.SetResumeID("")
91
-	}
92
-	return
93
-}
94
-
95
-// Delete stops tracking a client's resume token.
96
-func (rm *ResumeManager) Delete(client *Client) {
97
-	rm.Lock()
98
-	defer rm.Unlock()
99
-
100
-	currentID := client.ResumeID()
101
-	if currentID != "" {
102
-		delete(rm.resumeIDtoCreds, currentID)
103
-	}
104
-}

+ 0
- 8
irc/server.go View File

@@ -80,7 +80,6 @@ type Server struct {
80 80
 	rehashMutex       sync.Mutex // tier 4
81 81
 	rehashSignal      chan os.Signal
82 82
 	pprofServer       *http.Server
83
-	resumeManager     ResumeManager
84 83
 	signals           chan os.Signal
85 84
 	snomasks          SnoManager
86 85
 	store             *buntdb.DB
@@ -106,7 +105,6 @@ func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
106 105
 
107 106
 	server.clients.Initialize()
108 107
 	server.semaphores.Initialize()
109
-	server.resumeManager.Initialize(server)
110 108
 	server.whoWas.Initialize(config.Limits.WhowasEntries)
111 109
 	server.monitorManager.Initialize()
112 110
 	server.snomasks.Initialize()
@@ -273,12 +271,6 @@ func (server *Server) handleAlwaysOnExpirations() {
273 271
 //
274 272
 
275 273
 func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
276
-	// if the session just sent us a RESUME line, try to resume
277
-	if session.resumeDetails != nil {
278
-		session.tryResume()
279
-		return // whether we succeeded or failed, either way `c` is not getting registered
280
-	}
281
-
282 274
 	// XXX PROXY or WEBIRC MUST be sent as the first line of the session;
283 275
 	// if we are here at all that means we have the final value of the IP
284 276
 	if session.rawHostname == "" {

Loading…
Cancel
Save