fix lint and steal autofocus on registration to seed

This commit is contained in:
audric 2021-08-06 14:23:08 +10:00
parent 2ebae9a746
commit e9412df60e
7 changed files with 170 additions and 152 deletions

View File

@ -11,6 +11,9 @@ js/util_worker.js
libtextsecure/components.js libtextsecure/components.js
libtextsecure/test/test.js libtextsecure/test/test.js
test/test.js test/test.js
libloki/test/components.js
libloki/test/test.js
# Third-party files # Third-party files
js/Mp3LameEncoder.min.js js/Mp3LameEncoder.min.js

View File

@ -492,7 +492,8 @@
return ( return (
e(t) || (t = o(t)), e(t) || (t = o(t)),
(this.unsigned === t.unsigned || this.high >>> 31 != 1 || t.high >>> 31 != 1) && (this.unsigned === t.unsigned || this.high >>> 31 != 1 || t.high >>> 31 != 1) &&
this.high === t.high && this.low === t.low this.high === t.high &&
this.low === t.low
); );
}), }),
(B.eq = B.equals), (B.eq = B.equals),

View File

@ -8116,14 +8116,9 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*istanbul ignore start*/ function _interopRequireDefault(obj) { /*istanbul ignore start*/ function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj }; return obj && obj.__esModule ? obj : { default: obj };
} // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode } // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode // // Ranges and exceptions: // Latin-1 Supplement, 008000FF // - U+00D7 × Multiplication sign // - U+00F7 ÷ Division sign
/*istanbul ignore end*/ // /*istanbul ignore end*/ // Latin Extended-A, 0100017F
// Ranges and exceptions:
// Latin-1 Supplement, 008000FF
// - U+00D7 × Multiplication sign
// - U+00F7 ÷ Division sign
// Latin Extended-A, 0100017F
// Latin Extended-B, 0180024F // Latin Extended-B, 0180024F
// IPA Extensions, 025002AF // IPA Extensions, 025002AF
// Spacing Modifier Letters, 02B002FF // Spacing Modifier Letters, 02B002FF
@ -8176,10 +8171,12 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}; };
function diffWords(oldStr, newStr, options) { function diffWords(oldStr, newStr, options) {
options = /*istanbul ignore start*/ (0, options = /*istanbul ignore start*/ (0, _params.generateOptions)(
_params.generateOptions)(/*istanbul ignore end*/ options, { /*istanbul ignore end*/ options,
ignoreWhitespace: true, {
}); ignoreWhitespace: true,
}
);
return wordDiff.diff(oldStr, newStr, options); return wordDiff.diff(oldStr, newStr, options);
} }
@ -8267,10 +8264,12 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return lineDiff.diff(oldStr, newStr, callback); return lineDiff.diff(oldStr, newStr, callback);
} }
function diffTrimmedLines(oldStr, newStr, callback) { function diffTrimmedLines(oldStr, newStr, callback) {
var options = /*istanbul ignore start*/ (0, var options = /*istanbul ignore start*/ (0, _params.generateOptions)(
_params.generateOptions)(/*istanbul ignore end*/ callback, { /*istanbul ignore end*/ callback,
ignoreWhitespace: true, {
}); ignoreWhitespace: true,
}
);
return lineDiff.diff(oldStr, newStr, options); return lineDiff.diff(oldStr, newStr, options);
} }
@ -22562,7 +22561,8 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ( if (
!doLength && !doLength &&
objType === 'date' && (startType !== 'date' || finishType !== 'date') objType === 'date' &&
(startType !== 'date' || finishType !== 'date')
) { ) {
errorMessage = msgPrefix + 'the arguments to within must be dates'; errorMessage = msgPrefix + 'the arguments to within must be dates';
} else if ( } else if (

View File

@ -30,13 +30,15 @@ const RecoveryPhraseInput = (props: {
recoveryPhrase: string; recoveryPhrase: string;
onSeedChanged: (val: string) => any; onSeedChanged: (val: string) => any;
handlePressEnter: () => any; handlePressEnter: () => any;
stealAutoFocus?: boolean;
}) => { }) => {
return ( return (
// tslint:disable-next-line: use-simple-attributes
<SessionInput <SessionInput
label={window.i18n('recoveryPhrase')} label={window.i18n('recoveryPhrase')}
type="password" type="password"
value={props.recoveryPhrase} value={props.recoveryPhrase}
autoFocus={true} autoFocus={props.stealAutoFocus || false}
placeholder={window.i18n('enterRecoveryPhrase')} placeholder={window.i18n('enterRecoveryPhrase')}
enableShowHide={true} enableShowHide={true}
onValueChanged={props.onSeedChanged} onValueChanged={props.onSeedChanged}
@ -69,12 +71,14 @@ export const RegistrationUserDetails = (props: Props) => {
recoveryPhrase={props.recoveryPhrase as string} recoveryPhrase={props.recoveryPhrase as string}
handlePressEnter={props.handlePressEnter} handlePressEnter={props.handlePressEnter}
onSeedChanged={props.onSeedChanged as any} onSeedChanged={props.onSeedChanged as any}
stealAutoFocus={props.stealAutoFocus}
/> />
)} )}
<div className="inputfields"> <div className="inputfields">
{props.showDisplayNameField && ( {props.showDisplayNameField && (
// tslint:disable-next-line: use-simple-attributes
<DisplayNameInput <DisplayNameInput
stealAutoFocus={props.stealAutoFocus} stealAutoFocus={!props.showSeedField && props.stealAutoFocus}
displayName={props.displayName} displayName={props.displayName}
handlePressEnter={props.handlePressEnter} handlePressEnter={props.handlePressEnter}
onDisplayNameChanged={props.onDisplayNameChanged} onDisplayNameChanged={props.onDisplayNameChanged}

View File

@ -50,7 +50,7 @@ export const TextToBase64 = async (text: string) => {
}; };
export const textToArrayBuffer = async (text: string) => { export const textToArrayBuffer = async (text: string) => {
return await window.callWorker('bytesFromString', text); return window.callWorker('bytesFromString', text);
}; };
export const verifyED25519Signature = async ( export const verifyED25519Signature = async (
@ -58,12 +58,7 @@ export const verifyED25519Signature = async (
base64EncodedData: string, base64EncodedData: string,
base64EncondedSignature: string base64EncondedSignature: string
): Promise<Boolean> => { ): Promise<Boolean> => {
return await window.callWorker( return window.callWorker('verifySignature', pubkey, base64EncodedData, base64EncondedSignature);
'verifySignature',
pubkey,
base64EncodedData,
base64EncondedSignature
);
}; };
export const parseMessages = async ( export const parseMessages = async (

View File

@ -67,7 +67,7 @@ export class OpenGroupMessageV2 {
if (!signature || signature.length === 0) { if (!signature || signature.length === 0) {
throw new Error("Couldn't sign message"); throw new Error("Couldn't sign message");
} }
let base64Sig = await window.callWorker('arrayBufferToStringBase64', signature); const base64Sig = await window.callWorker('arrayBufferToStringBase64', signature);
return new OpenGroupMessageV2({ return new OpenGroupMessageV2({
base64EncodedData: this.base64EncodedData, base64EncodedData: this.base64EncodedData,
sentTimestamp: this.sentTimestamp, sentTimestamp: this.sentTimestamp,

View File

@ -32,7 +32,7 @@ import {
import { Snode } from '../../data/data'; import { Snode } from '../../data/data';
import { updateIsOnline } from '../../state/ducks/onion'; import { updateIsOnline } from '../../state/ducks/onion';
import { ed25519Str } from '../onions/onionPath'; import { ed25519Str } from '../onions/onionPath';
import { UserUtils, StringUtils } from '../utils'; import { StringUtils, UserUtils } from '../utils';
// ONS name can have [a-zA-Z0-9_-] except that - is not allowed as start or end // ONS name can have [a-zA-Z0-9_-] except that - is not allowed as start or end
// do not define a regex but rather create it on the fly to avoid https://stackoverflow.com/questions/3891641/regex-test-only-works-every-other-time // do not define a regex but rather create it on the fly to avoid https://stackoverflow.com/questions/3891641/regex-test-only-works-every-other-time
@ -607,7 +607,8 @@ export async function retrieveNextMessages(
* @param snode Snode to send request to * @param snode Snode to send request to
* @returns timestamp of the response from snode * @returns timestamp of the response from snode
*/ */
const getNetworkTime = async (snode: Snode): Promise<string | number> => { // tslint:disable-next-line: variable-name
export const TEST_getNetworkTime = async (snode: Snode): Promise<string | number> => {
const response: any = await snodeRpc('info', {}, snode); const response: any = await snodeRpc('info', {}, snode);
const body = JSON.parse(response.body); const body = JSON.parse(response.body);
const timestamp = body?.timestamp; const timestamp = body?.timestamp;
@ -625,139 +626,153 @@ export const forceNetworkDeletion = async (): Promise<Array<string> | null> => {
const userED25519KeyPair = await UserUtils.getUserED25519KeyPair(); const userED25519KeyPair = await UserUtils.getUserED25519KeyPair();
if (!userED25519KeyPair) { if (!userED25519KeyPair) {
window.log.warn('Cannot forceNetworkDeletion, did not find user ed25519 key.'); window?.log?.warn('Cannot forceNetworkDeletion, did not find user ed25519 key.');
return null; return null;
} }
const edKeyPriv = userED25519KeyPair.privKey; const edKeyPriv = userED25519KeyPair.privKey;
try { try {
const maliciousSnodes = await pRetry(async () => { const maliciousSnodes = await pRetry(
const userSwarm = await getSwarmFor(userX25519PublicKey); async () => {
const snodeToMakeRequestTo: Snode | undefined = _.sample(userSwarm); const userSwarm = await getSwarmFor(userX25519PublicKey);
const edKeyPrivBytes = fromHexToArray(edKeyPriv); const snodeToMakeRequestTo: Snode | undefined = _.sample(userSwarm);
const edKeyPrivBytes = fromHexToArray(edKeyPriv);
if (!snodeToMakeRequestTo) { if (!snodeToMakeRequestTo) {
window.log.warn('Cannot forceNetworkDeletion, without a valid swarm node.'); window?.log?.warn('Cannot forceNetworkDeletion, without a valid swarm node.');
return null; return null;
}
return pRetry(
async () => {
const timestamp = await getNetworkTime(snodeToMakeRequestTo);
const verificationData = StringUtils.encode(`delete_all${timestamp}`, 'utf8');
const message = new Uint8Array(verificationData);
const signature = sodium.crypto_sign_detached(message, edKeyPrivBytes);
const signatureBase64 = fromUInt8ArrayToBase64(signature);
const deleteMessageParams = {
pubkey: userX25519PublicKey,
pubkey_ed25519: userED25519KeyPair.pubKey.toUpperCase(),
timestamp,
signature: signatureBase64,
};
const ret = await snodeRpc(
'delete_all',
deleteMessageParams,
snodeToMakeRequestTo,
userX25519PublicKey
);
if (!ret) {
throw new Error(
`Empty response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}`
);
}
try {
const parsedResponse = JSON.parse(ret.body);
const { swarm } = parsedResponse;
if (!swarm) {
throw new Error(
`Invalid JSON swarm response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}, ${ret?.body}`
);
}
const swarmAsArray = Object.entries(swarm) as Array<Array<any>>;
if (!swarmAsArray.length) {
throw new Error(
`Invalid JSON swarmAsArray response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}, ${ret?.body}`
);
}
// results will only contains the snode pubkeys which returned invalid/empty results
const results: Array<string> = _.compact(
swarmAsArray.map(snode => {
const snodePubkey = snode[0];
const snodeJson = snode[1];
const isFailed = snodeJson.failed || false;
if (isFailed) {
const reason = snodeJson.reason;
const statusCode = snodeJson.code;
if (reason && statusCode) {
window.log.warn(
`Could not delete data from ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)} due to error: ${reason}: ${statusCode}`
);
} else {
window.log.warn(
`Could not delete data from ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}`
);
}
return snodePubkey;
}
const hashes = snodeJson.deleted as Array<string>;
const signatureSnode = snodeJson.signature as string;
// The signature format is ( PUBKEY_HEX || TIMESTAMP || DELETEDHASH[0] || ... || DELETEDHASH[N] )
const dataToVerify = `${userX25519PublicKey}${timestamp}${hashes.join('')}`;
const dataToVerifyUtf8 = StringUtils.encode(dataToVerify, 'utf8');
const isValid = sodium.crypto_sign_verify_detached(
fromBase64ToArray(signatureSnode),
new Uint8Array(dataToVerifyUtf8),
fromHexToArray(snodePubkey)
);
if (!isValid) {
return snodePubkey;
}
return null;
})
);
return results;
} catch (e) {
throw new Error(
`Invalid JSON response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}, ${ret?.body}`
);
}
},
{
retries: 3,
minTimeout: 500,
onFailedAttempt: e => {
window?.log?.warn(
`delete_all request attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left...`
);
},
} }
);
}, {}); return pRetry(
async () => {
const timestamp = await exports.TEST_getNetworkTime(snodeToMakeRequestTo);
const verificationData = StringUtils.encode(`delete_all${timestamp}`, 'utf8');
const message = new Uint8Array(verificationData);
const signature = sodium.crypto_sign_detached(message, edKeyPrivBytes);
const signatureBase64 = fromUInt8ArrayToBase64(signature);
const deleteMessageParams = {
pubkey: userX25519PublicKey,
pubkey_ed25519: userED25519KeyPair.pubKey.toUpperCase(),
timestamp,
signature: signatureBase64,
};
const ret = await snodeRpc(
'delete_all',
deleteMessageParams,
snodeToMakeRequestTo,
userX25519PublicKey
);
if (!ret) {
throw new Error(
`Empty response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}`
);
}
try {
const parsedResponse = JSON.parse(ret.body);
const { swarm } = parsedResponse;
if (!swarm) {
throw new Error(
`Invalid JSON swarm response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}, ${ret?.body}`
);
}
const swarmAsArray = Object.entries(swarm) as Array<Array<any>>;
if (!swarmAsArray.length) {
throw new Error(
`Invalid JSON swarmAsArray response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}, ${ret?.body}`
);
}
// results will only contains the snode pubkeys which returned invalid/empty results
const results: Array<string> = _.compact(
swarmAsArray.map(snode => {
const snodePubkey = snode[0];
const snodeJson = snode[1];
const isFailed = snodeJson.failed || false;
if (isFailed) {
const reason = snodeJson.reason;
const statusCode = snodeJson.code;
if (reason && statusCode) {
window?.log?.warn(
`Could not delete data from ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)} due to error: ${reason}: ${statusCode}`
);
} else {
window?.log?.warn(
`Could not delete data from ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}`
);
}
return snodePubkey;
}
const hashes = snodeJson.deleted as Array<string>;
const signatureSnode = snodeJson.signature as string;
// The signature format is ( PUBKEY_HEX || TIMESTAMP || DELETEDHASH[0] || ... || DELETEDHASH[N] )
const dataToVerify = `${userX25519PublicKey}${timestamp}${hashes.join('')}`;
const dataToVerifyUtf8 = StringUtils.encode(dataToVerify, 'utf8');
const isValid = sodium.crypto_sign_verify_detached(
fromBase64ToArray(signatureSnode),
new Uint8Array(dataToVerifyUtf8),
fromHexToArray(snodePubkey)
);
if (!isValid) {
return snodePubkey;
}
return null;
})
);
return results;
} catch (e) {
throw new Error(
`Invalid JSON response got for delete_all on snode ${ed25519Str(
snodeToMakeRequestTo.pubkey_ed25519
)}, ${ret?.body}`
);
}
},
{
retries: 3,
minTimeout: exports.TEST_getMinTimeout(),
onFailedAttempt: e => {
window?.log?.warn(
`delete_all INNER request attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left...`
);
},
}
);
},
{
retries: 3,
minTimeout: exports.TEST_getMinTimeout(),
onFailedAttempt: e => {
window?.log?.warn(
`delete_all OUTER request attempt #${e.attemptNumber} failed. ${e.retriesLeft} retries left...`
);
},
}
);
return maliciousSnodes; return maliciousSnodes;
} catch (e) { } catch (e) {
window.log.warn('failed to delete everything on network:', e); window?.log?.warn('failed to delete everything on network:', e);
return null; return null;
} }
}; };
// tslint:disable-next-line: variable-name
export const TEST_getMinTimeout = () => 500;