Merge "MCR: Add temporary web UI mcrundo action"
[lhc/web/wiklou.git] / resources / src / mediawiki.user.js
1 /**
2 * @class mw.user
3 * @singleton
4 */
5 /* global Uint16Array */
6 ( function ( mw, $ ) {
7 var userInfoPromise, pageviewRandomId;
8
9 /**
10 * Get the current user's groups or rights
11 *
12 * @private
13 * @return {jQuery.Promise}
14 */
15 function getUserInfo() {
16 if ( !userInfoPromise ) {
17 userInfoPromise = new mw.Api().getUserInfo();
18 }
19 return userInfoPromise;
20 }
21
22 // mw.user with the properties options and tokens gets defined in mediawiki.js.
23 $.extend( mw.user, {
24
25 /**
26 * Generate a random user session ID.
27 *
28 * This information would potentially be stored in a cookie to identify a user during a
29 * session or series of sessions. Its uniqueness should not be depended on unless the
30 * browser supports the crypto API.
31 *
32 * Known problems with Math.random():
33 * Using the Math.random function we have seen sets
34 * with 1% of non uniques among 200,000 values with Safari providing most of these.
35 * Given the prevalence of Safari in mobile the percentage of duplicates in
36 * mobile usages of this code is probably higher.
37 *
38 * Rationale:
39 * We need about 80 bits to make sure that probability of collision
40 * on 155 billion is <= 1%
41 *
42 * See https://en.wikipedia.org/wiki/Birthday_attack#Mathematics
43 * n(p;H) = n(0.01,2^80)= sqrt (2 * 2^80 * ln(1/(1-0.01)))
44
45 * @return {string} 80 bit integer in hex format, padded
46 */
47 generateRandomSessionId: function () {
48 var rnds, i,
49 hexRnds = new Array( 5 ),
50 // Support: IE 11
51 crypto = window.crypto || window.msCrypto;
52
53 if ( crypto && crypto.getRandomValues && typeof Uint16Array === 'function' ) {
54
55 // Fill an array with 5 random values, each of which is 16 bits.
56 // Note that Uint16Array is array-like but does not implement Array.
57 rnds = new Uint16Array( 5 );
58 crypto.getRandomValues( rnds );
59
60 } else {
61
62 // 0x10000 is 2^16 so the operation below will return a number
63 // between 2^16 and zero
64 for ( i = 0; i < 5; i++ ) {
65 rnds[ i ] = Math.floor( Math.random() * 0x10000 );
66 }
67 }
68 // Convert the 5 16bit-numbers into 20 characters (4 hex chars per 16 bits)
69 for ( i = 0; i < 5; i++ ) {
70 // Add 0x1000 before converting to hex and strip the extra character
71 // after converting to keep the leading zeros.
72 hexRnds[ i ] = ( rnds[ i ] + 0x10000 ).toString( 16 ).slice( 1 );
73 }
74
75 // Concatenation of two random integers with entropy n and m
76 // returns a string with entropy n+m if those strings are independent
77 return hexRnds.join( '' );
78 },
79
80 /**
81 * A sticky generateRandomSessionId for the current JS execution context,
82 * cached within this class (also known as a page view token).
83 *
84 * @since 1.32
85 * @return {string} 64 bit integer in hex format, padded
86 */
87 getPageviewToken: function () {
88 if ( !pageviewRandomId ) {
89 pageviewRandomId = mw.user.generateRandomSessionId();
90 }
91
92 return pageviewRandomId;
93 },
94
95 /**
96 * Get the current user's database id
97 *
98 * Not to be confused with #id.
99 *
100 * @return {number} Current user's id, or 0 if user is anonymous
101 */
102 getId: function () {
103 return mw.config.get( 'wgUserId' ) || 0;
104 },
105
106 /**
107 * Get the current user's name
108 *
109 * @return {string|null} User name string or null if user is anonymous
110 */
111 getName: function () {
112 return mw.config.get( 'wgUserName' );
113 },
114
115 /**
116 * Get date user registered, if available
117 *
118 * @return {boolean|null|Date} False for anonymous users, null if data is
119 * unavailable, or Date for when the user registered.
120 */
121 getRegistration: function () {
122 var registration;
123 if ( mw.user.isAnon() ) {
124 return false;
125 }
126 registration = mw.config.get( 'wgUserRegistration' );
127 // Registration may be unavailable if the user signed up before MediaWiki
128 // began tracking this.
129 return !registration ? null : new Date( registration );
130 },
131
132 /**
133 * Whether the current user is anonymous
134 *
135 * @return {boolean}
136 */
137 isAnon: function () {
138 return mw.user.getName() === null;
139 },
140
141 /**
142 * Get an automatically generated random ID (persisted in sessionStorage)
143 *
144 * This ID is ephemeral for everyone, staying in their browser only until they
145 * close their browsing session.
146 *
147 * @return {string} Random session ID
148 */
149 sessionId: function () {
150 var sessionId = mw.storage.session.get( 'mwuser-sessionId' );
151 if ( !sessionId ) {
152 sessionId = mw.user.generateRandomSessionId();
153 mw.storage.session.set( 'mwuser-sessionId', sessionId );
154 }
155 return sessionId;
156 },
157
158 /**
159 * Get the current user's name or the session ID
160 *
161 * Not to be confused with #getId.
162 *
163 * @return {string} User name or random session ID
164 */
165 id: function () {
166 return mw.user.getName() || mw.user.sessionId();
167 },
168
169 /**
170 * Get the current user's groups
171 *
172 * @param {Function} [callback]
173 * @return {jQuery.Promise}
174 */
175 getGroups: function ( callback ) {
176 var userGroups = mw.config.get( 'wgUserGroups', [] );
177
178 // Uses promise for backwards compatibility
179 return $.Deferred().resolve( userGroups ).done( callback );
180 },
181
182 /**
183 * Get the current user's rights
184 *
185 * @param {Function} [callback]
186 * @return {jQuery.Promise}
187 */
188 getRights: function ( callback ) {
189 return getUserInfo().then(
190 function ( userInfo ) { return userInfo.rights; },
191 function () { return []; }
192 ).done( callback );
193 }
194 } );
195
196 /**
197 * @method stickyRandomId
198 * @deprecated since 1.32 use getPageviewToken instead
199 */
200 mw.log.deprecate( mw.user, 'stickyRandomId', mw.user.getPageviewToken, 'Please use getPageviewToken instead' );
201
202 }( mediaWiki, jQuery ) );