Implemented client
This commit is contained in:
		
							parent
							
								
									955644c5be
								
							
						
					
					
						commit
						2a02e7255b
					
				
							
								
								
									
										265
									
								
								client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								client.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,265 @@ | |||
| package rumble | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"net/http/cookiejar" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	domain                 = "rumble.com" | ||||
| 	urlBase                = "https://" + domain | ||||
| 	urlAccount             = urlBase + "/account" | ||||
| 	urlService             = urlBase + "/service.php?name=" | ||||
| 	urlServiceUserGetSalts = urlService + "user.get_salts" | ||||
| 	urlServiceUserLogin    = urlService + "user.login" | ||||
| 	urlServiceUserLogout   = urlService + "user.logout" | ||||
| ) | ||||
| 
 | ||||
| type Client struct { | ||||
| 	httpClient *http.Client | ||||
| } | ||||
| 
 | ||||
| type NewClientOptions struct { | ||||
| 	Cookies []*http.Cookie | ||||
| } | ||||
| 
 | ||||
| func NewClient(opts NewClientOptions) (*Client, error) { | ||||
| 	cl, err := newHttpClient(opts.Cookies) | ||||
| 	if err != nil { | ||||
| 		return nil, pkgErr("error creating new http client: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return &Client{httpClient: cl}, nil | ||||
| } | ||||
| 
 | ||||
| func newHttpClient(cookies []*http.Cookie) (*http.Client, error) { | ||||
| 	jar, err := cookiejar.New(nil) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error creating cookiejar: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	url, err := url.Parse(urlBase) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error parsing url: %v", err) | ||||
| 	} | ||||
| 	jar.SetCookies(url, cookies) | ||||
| 
 | ||||
| 	return &http.Client{Jar: jar}, nil | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Login(username string, password string) ([]*http.Cookie, error) { | ||||
| 	if c.httpClient == nil { | ||||
| 		return nil, pkgErr("", fmt.Errorf("http client is nil")) | ||||
| 	} | ||||
| 
 | ||||
| 	salts, err := c.getSalts(username) | ||||
| 	if err != nil { | ||||
| 		return nil, pkgErr("error getting salts: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	cookies, err := c.login(username, password, salts) | ||||
| 	if err != nil { | ||||
| 		return nil, pkgErr("error logging in", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return cookies, nil | ||||
| } | ||||
| 
 | ||||
| type GetSaltsData struct { | ||||
| 	Salts []string `json:"salts"` | ||||
| } | ||||
| 
 | ||||
| type GetSaltsResponse struct { | ||||
| 	Data GetSaltsData `json:"data"` | ||||
| } | ||||
| 
 | ||||
| func (c *Client) getSalts(username string) ([]string, error) { | ||||
| 	u := url.URL{} | ||||
| 	q := u.Query() | ||||
| 	q.Add("username", username) | ||||
| 	body := q.Encode() | ||||
| 
 | ||||
| 	resp, err := c.httpClient.Post(urlServiceUserGetSalts, "application/x-www-form-urlencoded", strings.NewReader(body)) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("http post request returned error: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		return nil, fmt.Errorf("http post response status not %s: %s", http.StatusText(http.StatusOK), resp.Status) | ||||
| 	} | ||||
| 
 | ||||
| 	bodyB, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error reading response body: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	var gsr GetSaltsResponse | ||||
| 	err = json.NewDecoder(strings.NewReader(string(bodyB))).Decode(&gsr) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error decoding response body: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return gsr.Data.Salts, nil | ||||
| } | ||||
| 
 | ||||
| func (c *Client) login(username string, password string, salts []string) ([]*http.Cookie, error) { | ||||
| 	hashes, err := hash(password, salts) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error generating password hashes: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	u := url.URL{} | ||||
| 	q := u.Query() | ||||
| 	q.Add("username", username) | ||||
| 	q.Add("password_hashes", hashes) | ||||
| 	body := q.Encode() | ||||
| 	resp, err := c.httpClient.Post(urlServiceUserLogin, "application/x-www-form-urlencoded", strings.NewReader(body)) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("http post request returned error: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		return nil, fmt.Errorf("http post response status not %s: %s", http.StatusText(http.StatusOK), resp.Status) | ||||
| 	} | ||||
| 
 | ||||
| 	bodyB, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error reading response body: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	session, err := loginSession(bodyB) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error getting login session: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if session == "false" { | ||||
| 		return nil, fmt.Errorf("failed to log in ") | ||||
| 	} | ||||
| 
 | ||||
| 	return resp.Cookies(), nil | ||||
| } | ||||
| 
 | ||||
| func hash(password string, salts []string) (string, error) { | ||||
| 	vm := otto.New() | ||||
| 
 | ||||
| 	vm.Set("password", password) | ||||
| 	vm.Set("salt0", salts[0]) | ||||
| 	vm.Set("salt1", salts[1]) | ||||
| 	vm.Set("salt2", salts[2]) | ||||
| 
 | ||||
| 	_, err := vm.Run(md5) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("error running md5 javascript: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	hashesV, err := vm.Get("hashes") | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("error getting hashes: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	hashesS, err := hashesV.ToString() | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("error converting hashes value to string: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return hashesS, nil | ||||
| } | ||||
| 
 | ||||
| type LoginSessionDataBool struct { | ||||
| 	Session bool `json:"session"` | ||||
| } | ||||
| 
 | ||||
| type LoginSessionBool struct { | ||||
| 	Data LoginSessionDataBool `json:"data"` | ||||
| } | ||||
| 
 | ||||
| type LoginSessionDataString struct { | ||||
| 	Session string `json:"session"` | ||||
| } | ||||
| 
 | ||||
| type LoginSessionString struct { | ||||
| 	Data LoginSessionDataString `json:"data"` | ||||
| } | ||||
| 
 | ||||
| func loginSession(body []byte) (string, error) { | ||||
| 	bodyS := string(body) | ||||
| 
 | ||||
| 	var lss LoginSessionString | ||||
| 	err := json.NewDecoder(strings.NewReader(bodyS)).Decode(&lss) | ||||
| 	if err == nil { | ||||
| 		return lss.Data.Session, nil | ||||
| 	} | ||||
| 
 | ||||
| 	var lsb LoginSessionBool | ||||
| 	err = json.NewDecoder(strings.NewReader(bodyS)).Decode(&lsb) | ||||
| 	if err == nil { | ||||
| 		return "false", nil | ||||
| 	} | ||||
| 
 | ||||
| 	return "", fmt.Errorf("error decoding response body") | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Logout() error { | ||||
| 	if c.httpClient == nil { | ||||
| 		return pkgErr("", fmt.Errorf("http client is nil")) | ||||
| 	} | ||||
| 
 | ||||
| 	err := c.logout() | ||||
| 	if err != nil { | ||||
| 		return pkgErr("error logging out", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *Client) logout() error { | ||||
| 	resp, err := c.httpClient.Get(urlServiceUserLogout) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("http get request returned error: %v", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		return fmt.Errorf("http get response status not %s: %s", http.StatusText(http.StatusOK), resp.Status) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type LoggedInResponseUser struct { | ||||
| 	LoggedIn bool `json:"logged_in"` | ||||
| } | ||||
| 
 | ||||
| type LoggedInResponse struct { | ||||
| 	User LoggedInResponseUser `json:"user"` | ||||
| } | ||||
| 
 | ||||
| func (c *Client) LoggedIn() (bool, error) { | ||||
| 	resp, err := c.httpClient.Get(urlServiceUserLogin) | ||||
| 	if err != nil { | ||||
| 		return false, pkgErr("http get request returned error", err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		return false, fmt.Errorf("http get response status not %s: %s", http.StatusText(http.StatusOK), resp.Status) | ||||
| 	} | ||||
| 
 | ||||
| 	bodyB, err := io.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return false, pkgErr("error reading response body", err) | ||||
| 	} | ||||
| 
 | ||||
| 	var lir LoggedInResponse | ||||
| 	err = json.NewDecoder(strings.NewReader(string(bodyB))).Decode(&lir) | ||||
| 	if err != nil { | ||||
| 		return false, pkgErr("error un-marshaling response body", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return lir.User.LoggedIn, nil | ||||
| } | ||||
							
								
								
									
										14
									
								
								error.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								error.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| package rumble | ||||
| 
 | ||||
| import "fmt" | ||||
| 
 | ||||
| const pkgName = "rumble" | ||||
| 
 | ||||
| func pkgErr(prefix string, err error) error { | ||||
| 	pkgErr := pkgName | ||||
| 	if prefix != "" { | ||||
| 		pkgErr = fmt.Sprintf("%s: %s", pkgErr, prefix) | ||||
| 	} | ||||
| 
 | ||||
| 	return fmt.Errorf("%s: %v", pkgErr, err) | ||||
| } | ||||
							
								
								
									
										9
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| module github.com/tylertravisty/rumble-lib-go | ||||
| 
 | ||||
| go 1.22.2 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/robertkrimen/otto v0.4.0 // indirect | ||||
| 	golang.org/x/text v0.4.0 // indirect | ||||
| 	gopkg.in/sourcemap.v1 v1.0.5 // indirect | ||||
| ) | ||||
							
								
								
									
										6
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| github.com/robertkrimen/otto v0.4.0 h1:/c0GRrK1XDPcgIasAsnlpBT5DelIeB9U/Z/JCQsgr7E= | ||||
| github.com/robertkrimen/otto v0.4.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw= | ||||
| golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= | ||||
| golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||||
| gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= | ||||
| gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= | ||||
							
								
								
									
										85
									
								
								md5.js.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								md5.js.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| package rumble | ||||
| 
 | ||||
| const md5 = ` | ||||
| /* @license | ||||
|  * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 | ||||
|  * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | ||||
|  * Distributed under the BSD License | ||||
|  * See http://pajhome.org.uk/crypt/md5 for more info.
 | ||||
|  */ | ||||
| 
 | ||||
| md5 = function() { | ||||
| 	function n(){ | ||||
|         this.hex="0123456789abcdef".split("") | ||||
|     } | ||||
|     return n.prototype={ | ||||
|         hash:function(n){ | ||||
|             var h=this; | ||||
|             return h.binHex(h.binHash(h.strBin(n),n.length<<3)) | ||||
|         }, | ||||
|         hashUTF8:function(n){ | ||||
|             return this.hash(this.encUTF8(n)) | ||||
|         }, | ||||
|         hashRaw:function(n){ | ||||
|             var h=this; | ||||
|             return h.binStr(h.binHash(h.strBin(n),n.length<<3)) | ||||
|         }, | ||||
|         hashRawUTF8:function(n){ | ||||
|             return this.hashRaw(this.encUTF8(n)) | ||||
|         }, | ||||
|         hashStretch:function(n,h,i){ | ||||
|             return this.binHex(this.binHashStretch(n,h,i)) | ||||
|         }, | ||||
|         binHashStretch:function(n,h,i){ | ||||
|             var t,r,f=this,n=f.encUTF8(n),e=h+n,g=32+n.length<<3,o=f.strBin(n),a=o.length,e=f.binHash(f.strBin(e),e.length<<3); | ||||
|             for(i=i||1024,t=0;t<i;t++){ | ||||
|                 for(e=f.binHexBin(e),r=0;r<a;r++)e[8+r]=o[r];e=f.binHash(e,g) | ||||
|             } | ||||
|             return e | ||||
|         }, | ||||
|         encUTF8:function(n){ | ||||
|             for(var h,i,t="",r=0,f=n.length-1;r<=f;)h=n.charCodeAt(r++),r<f&&55296<=h&&h<=56319&&56320<=(i=n.charCodeAt(r))&&i<=57343&&(h=65536+((1023&h)<<10)+(1023&i),r++),h<=127?t+=String.fromCharCode(h):h<=2047?t+=String.fromCharCode(192|h>>>6&31,128|63&h):h<=65535?t+=String.fromCharCode(224|h>>>12&15,128|h>>>6&63,128|63&h):h<=2097151&&(t+=String.fromCharCode(240|h>>>18&7,128|h>>>12&63,128|h>>>6&63,128|63&h)); | ||||
|             return t | ||||
|         }, | ||||
|         strBin:function(n){ | ||||
|             for(var h=n.length<<3,i=[],t=0;t<h;t+=8)i[t>>5]|=(255&n.charCodeAt(t>>3))<<(31&t); | ||||
|             return i | ||||
|         }, | ||||
|         binHex:function(n){ | ||||
|             for(var h,i,t="",r=n.length<<5,f=0;f<r;f+=8)i=(h=n[f>>5]>>>(31&f)&255)>>>4&15,t+=this.hex[i]+this.hex[h&=15]; | ||||
|             return t | ||||
|         }, | ||||
|         binStr:function(n){ | ||||
|             for(var h,i="",t=n.length<<5,r=0;r<t;r+=8)h=n[r>>5]>>>(31&r)&255,i+=String.fromCharCode(h); | ||||
|             return i | ||||
|         }, | ||||
|         binHexBin:function(n){ | ||||
|             for(var h,i,t=n.length<<5,r=[],f=0;f<t;f+=8)i=(h=n[f>>5]>>>(31&f)&255)>>>4&15,r[f>>4]|=(9<i?87:48)+i+((9<(h&=15)?87:48)+h<<8)<<((15&f)<<1); | ||||
|             return r | ||||
|         }, | ||||
|         ff:function(n,h,i,t,r,f,e){ | ||||
|             i=h&i|~h&t,t=(65535&n)+(65535&i)+(65535&r)+(65535&e); | ||||
|             return((i=(i=(n>>16)+(i>>16)+(r>>16)+(e>>16)+(t>>16)<<16|65535&t)<<f|i>>>32-f)>>16)+(h>>16)+((t=(65535&i)+(65535&h))>>16)<<16|65535&t | ||||
|         }, | ||||
|         gg:function(n,h,i,t,r,f,e){ | ||||
|             i=h&t|i&~t,t=(65535&n)+(65535&i)+(65535&r)+(65535&e); | ||||
|             return((i=(i=(n>>16)+(i>>16)+(r>>16)+(e>>16)+(t>>16)<<16|65535&t)<<f|i>>>32-f)>>16)+(h>>16)+((t=(65535&i)+(65535&h))>>16)<<16|65535&t | ||||
|         }, | ||||
|         hh:function(n,h,i,t,r,f,e){ | ||||
|             i=h^i^t,t=(65535&n)+(65535&i)+(65535&r)+(65535&e); | ||||
|             return((i=(i=(n>>16)+(i>>16)+(r>>16)+(e>>16)+(t>>16)<<16|65535&t)<<f|i>>>32-f)>>16)+(h>>16)+((t=(65535&i)+(65535&h))>>16)<<16|65535&t | ||||
|         }, | ||||
|         ii:function(n,h,i,t,r,f,e){ | ||||
|             i^=h|~t,t=(65535&n)+(65535&i)+(65535&r)+(65535&e); | ||||
|             return((i=(i=(n>>16)+(i>>16)+(r>>16)+(e>>16)+(t>>16)<<16|65535&t)<<f|i>>>32-f)>>16)+(h>>16)+((t=(65535&i)+(65535&h))>>16)<<16|65535&t | ||||
|         }, | ||||
|         binHash:function(n,h){ | ||||
|             var i,t,r,f,e,g,o=1732584193,a=-271733879,u=-1732584194,s=271733878,c=this;for(n[h>>5]|=128<<(31&h),n[14+(h+64>>>9<<4)]=h,i=n.length,t=0;t<i;t+=16)g=o,r=a,f=u,e=s,o=c.ff(o,a,u,s,n[t+0],7,-680876936),s=c.ff(s,o,a,u,n[t+1],12,-389564586),u=c.ff(u,s,o,a,n[t+2],17,606105819),a=c.ff(a,u,s,o,n[t+3],22,-1044525330),o=c.ff(o,a,u,s,n[t+4],7,-176418897),s=c.ff(s,o,a,u,n[t+5],12,1200080426),u=c.ff(u,s,o,a,n[t+6],17,-1473231341),a=c.ff(a,u,s,o,n[t+7],22,-45705983),o=c.ff(o,a,u,s,n[t+8],7,1770035416),s=c.ff(s,o,a,u,n[t+9],12,-1958414417),u=c.ff(u,s,o,a,n[t+10],17,-42063),a=c.ff(a,u,s,o,n[t+11],22,-1990404162),o=c.ff(o,a,u,s,n[t+12],7,1804603682),s=c.ff(s,o,a,u,n[t+13],12,-40341101),u=c.ff(u,s,o,a,n[t+14],17,-1502002290),a=c.ff(a,u,s,o,n[t+15],22,1236535329),o=c.gg(o,a,u,s,n[t+1],5,-165796510),s=c.gg(s,o,a,u,n[t+6],9,-1069501632),u=c.gg(u,s,o,a,n[t+11],14,643717713),a=c.gg(a,u,s,o,n[t+0],20,-373897302),o=c.gg(o,a,u,s,n[t+5],5,-701558691),s=c.gg(s,o,a,u,n[t+10],9,38016083),u=c.gg(u,s,o,a,n[t+15],14,-660478335),a=c.gg(a,u,s,o,n[t+4],20,-405537848),o=c.gg(o,a,u,s,n[t+9],5,568446438),s=c.gg(s,o,a,u,n[t+14],9,-1019803690),u=c.gg(u,s,o,a,n[t+3],14,-187363961),a=c.gg(a,u,s,o,n[t+8],20,1163531501),o=c.gg(o,a,u,s,n[t+13],5,-1444681467),s=c.gg(s,o,a,u,n[t+2],9,-51403784),u=c.gg(u,s,o,a,n[t+7],14,1735328473),a=c.gg(a,u,s,o,n[t+12],20,-1926607734),o=c.hh(o,a,u,s,n[t+5],4,-378558),s=c.hh(s,o,a,u,n[t+8],11,-2022574463),u=c.hh(u,s,o,a,n[t+11],16,1839030562),a=c.hh(a,u,s,o,n[t+14],23,-35309556),o=c.hh(o,a,u,s,n[t+1],4,-1530992060),s=c.hh(s,o,a,u,n[t+4],11,1272893353),u=c.hh(u,s,o,a,n[t+7],16,-155497632),a=c.hh(a,u,s,o,n[t+10],23,-1094730640),o=c.hh(o,a,u,s,n[t+13],4,681279174),s=c.hh(s,o,a,u,n[t+0],11,-358537222),u=c.hh(u,s,o,a,n[t+3],16,-722521979),a=c.hh(a,u,s,o,n[t+6],23,76029189),o=c.hh(o,a,u,s,n[t+9],4,-640364487),s=c.hh(s,o,a,u,n[t+12],11,-421815835),u=c.hh(u,s,o,a,n[t+15],16,530742520),a=c.hh(a,u,s,o,n[t+2],23,-995338651),o=c.ii(o,a,u,s,n[t+0],6,-198630844),s=c.ii(s,o,a,u,n[t+7],10,1126891415),u=c.ii(u,s,o,a,n[t+14],15,-1416354905),a=c.ii(a,u,s,o,n[t+5],21,-57434055),o=c.ii(o,a,u,s,n[t+12],6,1700485571),s=c.ii(s,o,a,u,n[t+3],10,-1894986606),u=c.ii(u,s,o,a,n[t+10],15,-1051523),a=c.ii(a,u,s,o,n[t+1],21,-2054922799),o=c.ii(o,a,u,s,n[t+8],6,1873313359),s=c.ii(s,o,a,u,n[t+15],10,-30611744),u=c.ii(u,s,o,a,n[t+6],15,-1560198380),a=c.ii(a,u,s,o,n[t+13],21,1309151649),o=c.ii(o,a,u,s,n[t+4],6,-145523070),s=c.ii(s,o,a,u,n[t+11],10,-1120210379),u=c.ii(u,s,o,a,n[t+2],15,718787259),a=c.ii(a,u,s,o,n[t+9],21,-343485551),o=(o>>16)+(g>>16)+((g=(65535&o)+(65535&g))>>16)<<16|65535&g,a=(a>>16)+(r>>16)+((g=(65535&a)+(65535&r))>>16)<<16|65535&g,u=(u>>16)+(f>>16)+((g=(65535&u)+(65535&f))>>16)<<16|65535&g,s=(s>>16)+(e>>16)+((g=(65535&s)+(65535&e))>>16)<<16|65535&g; | ||||
|             return[o,a,u,s] | ||||
|         } | ||||
|     }, | ||||
|     new n | ||||
| }(); | ||||
| 
 | ||||
| hashes = [md5.hash(md5.hashStretch(password, salt0, 128) + salt1),md5.hashStretch(password, salt2, 128), salt1] | ||||
| ` | ||||
		Loading…
	
		Reference in a new issue
	
	 tyler
						tyler