<commit_before>"use strict";

var PushProcessor = require('./pushprocessor');

/**
 * This is an internal module. See {@link MatrixClient} for the public class.
 * @module client
 */
var EventEmitter = require("events").EventEmitter;
var q = require("q");

var httpApi = require("./http-api");
var MatrixEvent = require("./models/event").MatrixEvent;
var EventStatus = require("./models/event").EventStatus;
var StubStore = require("./store/stub");
var Room = require("./models/room");
var User = require("./models/user");
var webRtcCall = require("./webrtc/call");
var utils = require("./utils");

var CRYPTO_ENABLED = false;

try {
    var Olm = require("olm");
    if (Olm.Account && Olm.Session) {
        CRYPTO_ENABLED = true;
    }
} catch (e) {
    // Olm not installed.
}

// TODO:
// Internal: rate limiting

var OLM_ALGORITHM = "m.olm.v1.curve25519-aes-sha2";

/**
 * Construct a Matrix Client. Only directly construct this if you want to use
 * custom modules. Normally, {@link createClient} should be used
 * as it specifies 'sensible' defaults for these modules.
 * @constructor
 * @extends {external:EventEmitter}
 * @param {Object} opts The configuration options for this client.
 * @param {string} opts.baseUrl Required. The base URL to the client-server
 * HTTP API.
 * @param {string} opts.idBaseUrl Optional. The base identity server URL for
 * identity server requests.
 * @param {Function} opts.request Required. The function to invoke for HTTP
 * requests. The value of this property is typically <code>require("request")
 * </code> as it returns a function which meets the required interface. See
 * {@link requestFunction} for more information.
 * @param {string} opts.accessToken The access_token for this user.
 * @param {string} opts.userId The user ID for this user.
 * @param {Object} opts.store Optional. The data store to use. If not specified,
 * this client will not store any HTTP responses.
 * @param {Object} opts.scheduler Optional. The scheduler to use. If not
 * specified, this client will not retry requests on failure. This client
 * will supply its own processing function to
 * @param {Object} opts.queryParams Optional. Extra query parameters to append
 * to all requests with this client. Useful for application services which require
 * <code>?user_id=</code>.
 * {@link module:scheduler~MatrixScheduler#setProcessFunction}.
 */
function MatrixClient(opts) {
    utils.checkObjectHasKeys(opts, ["baseUrl", "request"]);

    this.baseUrl = opts.baseUrl;
    this.idBaseUrl = opts.idBaseUrl;

    this.store = opts.store || new StubStore();
    this.sessionStore = opts.sessionStore || null;
    this.accountKey = "DEFAULT_KEY";
    this.deviceId = opts.deviceId;
    if (CRYPTO_ENABLED && this.sessionStore !== null) {
        var e2eAccount = this.sessionStore.getEndToEndAccount();
        var account = new Olm.Account();
        try {
            if (e2eAccount === null) {
                account.create();
            } else {
                account.unpickle(this.accountKey, e2eAccount);
            }
            var e2eKeys = JSON.parse(account.identity_keys());
            var json = '{"algorithms":["' + OLM_ALGORITHM + '"]';
            json += ',"device_id":"' + this.deviceId + '"';
            json += ',"keys":';
            json += '{"ed25519:' + this.deviceId + '":';
            json += JSON.stringify(e2eKeys.ed25519);
            json += ',"curve25519:' + this.deviceId + '":';
            json += JSON.stringify(e2eKeys.curve25519);
            json += '}';
            json += ',"user_id":' + JSON.stringify(opts.userId);
            json += '}';
            var signature = account.sign(json);
            this.deviceKeys = JSON.parse(json);
            var signatures = {};
            signatures[opts.userId] = {};
            signatures[opts.userId]["ed25519:" + this.deviceId] = signature;
            this.deviceKeys.signatures = signatures;
            this.deviceCurve25519Key = e2eKeys.curve25519;
            var pickled = account.pickle(this.accountKey);
            this.sessionStore.storeEndToEndAccount(pickled);
            var myDevices = this.sessionStore.getEndToEndDevicesForUser(
                opts.userId
            ) || {};
            myDevices[opts.deviceId] = this.deviceKeys;
            this.sessionStore.storeEndToEndDevicesForUser(
                opts.userId, myDevices
            );
        } finally {
            account.free();
        }
    }
    this.scheduler = opts.scheduler;
    if (this.scheduler) {
        var self = this;
        this.scheduler.setProcessFunction(function(eventToSend) {
            eventToSend.status = EventStatus.SENDING;
            return _sendEventHttpRequest(self, eventToSend);
        });
    }
    this.clientRunning = false;

    var httpOpts = {
        baseUrl: opts.baseUrl,
        idBaseUrl: opts.idBaseUrl,
        accessToken: opts.accessToken,
        request: opts.request,
        prefix: httpApi.PREFIX_V1,
        onlyData: true,
        extraParams: opts.queryParams
    };
    this.credentials = {
        userId: (opts.userId || null)
    };
    this._http = new httpApi.MatrixHttpApi(httpOpts);
    this._syncingRooms = {
        // room_id: Promise
    };
    this.callList = {
        // callId: MatrixCall
    };

    // try constructing a MatrixCall to see if we are running in an environment
    // which has WebRTC. If we are, listen for and handle m.call.* events.
    var call = webRtcCall.createNewMatrixCall(this);
    this._supportsVoip = false;
    if (call) {
        setupCallEventHandler(this);
        this._supportsVoip = true;
    }

}
utils.inherits(MatrixClient, EventEmitter);

MatrixClient.prototype.getHsUrl = function() {
    return this.baseUrl;
}

MatrixClient.prototype.getIsUrl = function() {
    return this.idBaseUrl;
}

/**
 * Is end-to-end crypto enabled for this client.
 * @return {boolean} True if end-to-end is enabled.
 */
MatrixClient.prototype.isCryptoEnabled = function() {
    return CRYPTO_ENABLED && this.sessionStore !== null;
};


/**
 * Upload the device keys to the homeserver and ensure that the
 * homeserver has enough one-time keys.<commit_msg>Rename methods for getting homeserver and identity server URLs<commit_after>"use strict";

var PushProcessor = require('./pushprocessor');

/**
 * This is an internal module. See {@link MatrixClient} for the public class.
 * @module client
 */
var EventEmitter = require("events").EventEmitter;
var q = require("q");

var httpApi = require("./http-api");
var MatrixEvent = require("./models/event").MatrixEvent;
var EventStatus = require("./models/event").EventStatus;
var StubStore = require("./store/stub");
var Room = require("./models/room");
var User = require("./models/user");
var webRtcCall = require("./webrtc/call");
var utils = require("./utils");

var CRYPTO_ENABLED = false;

try {
    var Olm = require("olm");
    if (Olm.Account && Olm.Session) {
        CRYPTO_ENABLED = true;
    }
} catch (e) {
    // Olm not installed.
}

// TODO:
// Internal: rate limiting

var OLM_ALGORITHM = "m.olm.v1.curve25519-aes-sha2";

/**
 * Construct a Matrix Client. Only directly construct this if you want to use
 * custom modules. Normally, {@link createClient} should be used
 * as it specifies 'sensible' defaults for these modules.
 * @constructor
 * @extends {external:EventEmitter}
 * @param {Object} opts The configuration options for this client.
 * @param {string} opts.baseUrl Required. The base URL to the client-server
 * HTTP API.
 * @param {string} opts.idBaseUrl Optional. The base identity server URL for
 * identity server requests.
 * @param {Function} opts.request Required. The function to invoke for HTTP
 * requests. The value of this property is typically <code>require("request")
 * </code> as it returns a function which meets the required interface. See
 * {@link requestFunction} for more information.
 * @param {string} opts.accessToken The access_token for this user.
 * @param {string} opts.userId The user ID for this user.
 * @param {Object} opts.store Optional. The data store to use. If not specified,
 * this client will not store any HTTP responses.
 * @param {Object} opts.scheduler Optional. The scheduler to use. If not
 * specified, this client will not retry requests on failure. This client
 * will supply its own processing function to
 * @param {Object} opts.queryParams Optional. Extra query parameters to append
 * to all requests with this client. Useful for application services which require
 * <code>?user_id=</code>.
 * {@link module:scheduler~MatrixScheduler#setProcessFunction}.
 */
function MatrixClient(opts) {
    utils.checkObjectHasKeys(opts, ["baseUrl", "request"]);

    this.baseUrl = opts.baseUrl;
    this.idBaseUrl = opts.idBaseUrl;

    this.store = opts.store || new StubStore();
    this.sessionStore = opts.sessionStore || null;
    this.accountKey = "DEFAULT_KEY";
    this.deviceId = opts.deviceId;
    if (CRYPTO_ENABLED && this.sessionStore !== null) {
        var e2eAccount = this.sessionStore.getEndToEndAccount();
        var account = new Olm.Account();
        try {
            if (e2eAccount === null) {
                account.create();
            } else {
                account.unpickle(this.accountKey, e2eAccount);
            }
            var e2eKeys = JSON.parse(account.identity_keys());
            var json = '{"algorithms":["' + OLM_ALGORITHM + '"]';
            json += ',"device_id":"' + this.deviceId + '"';
            json += ',"keys":';
            json += '{"ed25519:' + this.deviceId + '":';
            json += JSON.stringify(e2eKeys.ed25519);
            json += ',"curve25519:' + this.deviceId + '":';
            json += JSON.stringify(e2eKeys.curve25519);
            json += '}';
            json += ',"user_id":' + JSON.stringify(opts.userId);
            json += '}';
            var signature = account.sign(json);
            this.deviceKeys = JSON.parse(json);
            var signatures = {};
            signatures[opts.userId] = {};
            signatures[opts.userId]["ed25519:" + this.deviceId] = signature;
            this.deviceKeys.signatures = signatures;
            this.deviceCurve25519Key = e2eKeys.curve25519;
            var pickled = account.pickle(this.accountKey);
            this.sessionStore.storeEndToEndAccount(pickled);
            var myDevices = this.sessionStore.getEndToEndDevicesForUser(
                opts.userId
            ) || {};
            myDevices[opts.deviceId] = this.deviceKeys;
            this.sessionStore.storeEndToEndDevicesForUser(
                opts.userId, myDevices
            );
        } finally {
            account.free();
        }
    }
    this.scheduler = opts.scheduler;
    if (this.scheduler) {
        var self = this;
        this.scheduler.setProcessFunction(function(eventToSend) {
            eventToSend.status = EventStatus.SENDING;
            return _sendEventHttpRequest(self, eventToSend);
        });
    }
    this.clientRunning = false;

    var httpOpts = {
        baseUrl: opts.baseUrl,
        idBaseUrl: opts.idBaseUrl,
        accessToken: opts.accessToken,
        request: opts.request,
        prefix: httpApi.PREFIX_V1,
        onlyData: true,
        extraParams: opts.queryParams
    };
    this.credentials = {
        userId: (opts.userId || null)
    };
    this._http = new httpApi.MatrixHttpApi(httpOpts);
    this._syncingRooms = {
        // room_id: Promise
    };
    this.callList = {
        // callId: MatrixCall
    };

    // try constructing a MatrixCall to see if we are running in an environment
    // which has WebRTC. If we are, listen for and handle m.call.* events.
    var call = webRtcCall.createNewMatrixCall(this);
    this._supportsVoip = false;
    if (call) {
        setupCallEventHandler(this);
        this._supportsVoip = true;
    }

}
utils.inherits(MatrixClient, EventEmitter);

/**
 * Get the Homserver URL of this client
 * @return {string} Homeserver URL of this client
 */
MatrixClient.prototype.getHomeserverUrl = function() {
    return this.baseUrl;
}

/**
 * Get the Identity Server URL of this client
 * @return {string} Identity Server URL of this client
 */
MatrixClient.prototype.getIdentityServerUrl = function() {
    return this.idBaseUrl;
}

/**
 * Is end-to-end crypto enabled for this client.
 * @return {boolean} True if end-to-end is enabled.
 */
MatrixClient.prototype.isCryptoEnabled = function() {
    return CRYPTO_ENABLED && this.sessionStore !== null;
};


/**
 * Upload the device keys to the homeserver and ensure that the
 * homeserver has enough one-time keys.
{'fraction_non_alphanumeric': 0.12069239320311259, 'fraction_numerical': 0.007940289026520565, 'mean_word_length': 2.7630714072303557, 'pattern_counts': {'":': 12, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2040826', 'n_tokens_mistral': 3697, 'n_tokens_neox': 3642, 'n_words': 1007}