mirror of
				https://github.com/ergochat/ergo.git
				synced 2025-10-31 05:47:22 +01:00 
			
		
		
		
	fix #696
This commit is contained in:
		
							parent
							
								
									9d56677691
								
							
						
					
					
						commit
						e143aaa83f
					
				| @ -206,7 +206,7 @@ func init() { | ||||
| 		}, | ||||
| 		"OPER": { | ||||
| 			handler:   operHandler, | ||||
| 			minParams: 2, | ||||
| 			minParams: 1, | ||||
| 		}, | ||||
| 		"PART": { | ||||
| 			handler:   partHandler, | ||||
|  | ||||
| @ -211,6 +211,7 @@ type OperConfig struct { | ||||
| 	Vhost     string | ||||
| 	WhoisLine string `yaml:"whois-line"` | ||||
| 	Password  string | ||||
| 	Certfp    string | ||||
| 	Modes     string | ||||
| } | ||||
| 
 | ||||
| @ -459,6 +460,7 @@ type Oper struct { | ||||
| 	WhoisLine string | ||||
| 	Vhost     string | ||||
| 	Pass      []byte | ||||
| 	Certfp    string | ||||
| 	Modes     []modes.ModeChange | ||||
| } | ||||
| 
 | ||||
| @ -479,6 +481,7 @@ func (conf *Config) Operators(oc map[string]*OperClass) (map[string]*Oper, error | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		oper.Certfp = opConf.Certfp | ||||
| 
 | ||||
| 		oper.Vhost = opConf.Vhost | ||||
| 		class, exists := oc[opConf.Class] | ||||
|  | ||||
| @ -2170,7 +2170,7 @@ func npcaHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // OPER <name> <password> | ||||
| // OPER <name> [password] | ||||
| func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { | ||||
| 	if client.HasMode(modes.Operator) { | ||||
| 		rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), "OPER", client.t("You're already opered-up!")) | ||||
| @ -2180,8 +2180,12 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp | ||||
| 	authorized := false | ||||
| 	oper := server.GetOperator(msg.Params[0]) | ||||
| 	if oper != nil { | ||||
| 		password := []byte(msg.Params[1]) | ||||
| 		authorized = (bcrypt.CompareHashAndPassword(oper.Pass, password) == nil) | ||||
| 		if utils.CertfpsMatch(oper.Certfp, client.certfp) { | ||||
| 			authorized = true | ||||
| 		} else if 1 < len(msg.Params) { | ||||
| 			password := []byte(msg.Params[1]) | ||||
| 			authorized = (bcrypt.CompareHashAndPassword(oper.Pass, password) == nil) | ||||
| 		} | ||||
| 	} | ||||
| 	if !authorized { | ||||
| 		rb.Add(nil, server.name, ERR_PASSWDMISMATCH, client.Nick(), client.t("Password incorrect")) | ||||
|  | ||||
| @ -349,7 +349,7 @@ The NPC command is used to send an action to the target as the source. | ||||
| Requires the roleplay mode (+E) to be set on the target.`, | ||||
| 	}, | ||||
| 	"oper": { | ||||
| 		text: `OPER <name> <password> | ||||
| 		text: `OPER <name> [password] | ||||
| 
 | ||||
| If the correct details are given, gives you IRCop privs.`, | ||||
| 	}, | ||||
|  | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"crypto/subtle" | ||||
| 	"encoding/base32" | ||||
| 	"encoding/base64" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| @ -68,3 +69,15 @@ func GenerateSecretKey() string { | ||||
| 	rand.Read(buf[:]) | ||||
| 	return base64.RawURLEncoding.EncodeToString(buf[:]) | ||||
| } | ||||
| 
 | ||||
| func normalizeCertfp(certfp string) string { | ||||
| 	return strings.ToLower(strings.Replace(certfp, ":", "", -1)) | ||||
| } | ||||
| 
 | ||||
| // Convenience to compare certfps as returned by different tools, e.g., openssl vs. oragono | ||||
| func CertfpsMatch(storedCertfp, suppliedCertfp string) bool { | ||||
| 	if storedCertfp == "" { | ||||
| 		return false | ||||
| 	} | ||||
| 	return normalizeCertfp(storedCertfp) == normalizeCertfp(suppliedCertfp) | ||||
| } | ||||
|  | ||||
| @ -81,3 +81,21 @@ func BenchmarkMungeSecretToken(b *testing.B) { | ||||
| 		t = MungeSecretToken(t) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestCertfpComparisons(t *testing.T) { | ||||
| 	opensslFP := "3D:6B:11:BF:B4:05:C3:F8:4B:38:CD:30:38:FB:EC:01:71:D5:03:54:79:04:07:88:4C:A5:5D:23:41:85:66:C9" | ||||
| 	oragonoFP := "3d6b11bfb405c3f84b38cd3038fbec0171d50354790407884ca55d23418566c9" | ||||
| 	badFP := "3d6b11bfb405c3f84b38cd3038fbec0171d50354790407884ca55d23418566c8" | ||||
| 	if !CertfpsMatch(opensslFP, oragonoFP) { | ||||
| 		t.Error("these certs should match") | ||||
| 	} | ||||
| 	if !CertfpsMatch(oragonoFP, opensslFP) { | ||||
| 		t.Error("these certs should match") | ||||
| 	} | ||||
| 	if CertfpsMatch("", "") { | ||||
| 		t.Error("empty stored certfp should not match empty provided certfp") | ||||
| 	} | ||||
| 	if CertfpsMatch(opensslFP, badFP) { | ||||
| 		t.Error("these certs should not match") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -121,7 +121,7 @@ server: | ||||
|         # one webirc block -- should correspond to one set of gateways | ||||
|         - | ||||
|             # tls fingerprint the gateway must connect with to use this webirc block | ||||
|             fingerprint: 938dd33f4b76dcaf7ce5eb25c852369cb4b8fb47ba22fc235aa29c6623a5f182 | ||||
|             fingerprint: "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" | ||||
| 
 | ||||
|             # password the gateway uses to connect, made with  oragono genpasswd | ||||
|             password: "$2a$04$sLEFDpIOyUp55e6gTMKbOeroT6tMXTjPFvA0eGvwvImVR9pkwv7ee" | ||||
| @ -449,6 +449,9 @@ opers: | ||||
|         # generated using  "oragono genpasswd" | ||||
|         password: "$2a$04$LiytCxaY0lI.guDj2pBN4eLRD5cdM2OLDwqmGAgB6M2OPirbF5Jcu" | ||||
| 
 | ||||
|         # being logged in with this client cert will let you /OPER without a password | ||||
|         certfp: "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" | ||||
| 
 | ||||
| # logging, takes inspiration from Insp | ||||
| logging: | ||||
|     - | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Shivaram Lingamneni
						Shivaram Lingamneni