Repository: louislam/uptime-kuma
File: server/notification-providers/teltonika.js (JavaScript)

Code before:
        // proto://host:port
        // Everything else should be stripped. Best way to validate is to use URL().

        let passedUrl = "";
        try {
            passedUrl = new URL(notification.teltonikaUrl);
        } catch (error) {
            throw Error("Invalid URL: " + notification.teltonikaUrl);
        }

        const baseUrl = passedUrl.origin;
        const loginUrl = baseUrl + "/api/login";
        const smsUrl = baseUrl + "/api/messages/actions/send";

        // Performing some input validation and cleanup for the other fields.
        let cleanUser = "";
        try {
            cleanUser = notification.teltonikaUsername.replace(/[^\x20-\x7F]/g, "").substring(0, 30);
            if (cleanUser.length >= 30) {
                throw Error("Username is longer than 30.");
            } else if (cleanUser.length < 1) {
                throw Error("Username is empty.");
            }
        } catch (error) {
            throw Error("Invalid input data for username.");
        }

        let cleanPass = "";
        try {
            cleanPass = notification.teltonikaPassword.replace(/[^\x20-\x7F]/g, "").substring(0, 40);

            if (cleanPass.length >= 30) {
                throw Error("Password is longer than 30.");
            } else if (cleanPass.length < 1) {
                throw Error("Password is empty.");
            }
        } catch (error) {
            throw Error("Invalid input data for password.");
        }

        let cleanModem = "";
        try {
            cleanModem = notification.teltonikaModem.replace(/[^\x2A-\x39]/g, "").substring(0, 5);

            if (cleanModem.length >= 5) {
                throw Error("Modem identifier is too long.");
            } else if (cleanModem.length < 1) {
                throw Error("Modem identifier is empty.");
            }
        } catch (error) {
            throw Error("Invalid input data for modem.");

Review comment (suggestion):
cannot throw elsewhere and because of the substring, longer usernames are validated

The same also applies below, where the code is just kind of doing things 2-3x.

```suggestion
        const cleanUser = notification.teltonikaUsername.replace(/[^\x20-\x7F]/g, "").substring(0, 30);
        if (!cleanUser) {
            throw Error("Username is empty.");
        }
```

Code after:
        const okMsg = "Sent Successfully.";

        // baseUrl is passed via the configuration screen.
        // Must be limited to _just_ the full origin, so: proto://host:port.
        // Everything else should be stripped. Best way to validate is to use URL().

        let passedUrl = "";
        try {
            passedUrl = new URL(notification.teltonikaUrl);
        } catch (error) {
            throw Error("Invalid URL: " + notification.teltonikaUrl);
        }

        const baseUrl = passedUrl.origin;
        const loginUrl = baseUrl + "/api/login";
        const smsUrl = baseUrl + "/api/messages/actions/send";

        // Teltonika SMS gateway supports a max of 160 chars for its messages.
        const cleanMsg = msg.substring(0, 159);

        // Starting communications with the API from here on out.
        try {
            let axiosConfig = {
                headers: {
                    "Content-Type": "application/json",
                    "cache-control": "no-cache",
                    Accept: "application/json",
                },
            };

            // In many cases, Teltonika routers will be setup using a self-signed
            // certificate. Here we give them an option to disable certificate
            // validation. It's not desirable, but sometimes the only option.
            if (notification.teltonikaUnsafeTls) {
                axiosConfig.httpsAgent = new https.Agent({
                    rejectUnauthorized: false, // Danger! Disables SSL verification
                });
            }

            axiosConfig = this.getAxiosConfigWithProxy(axiosConfig);

            // Logging in, to get an access token.
            // API reference https://developers.teltonika-networks.com/reference/rut241/7.19.4/v1.11.1/authentication
            // Teltonika's API access tokens expire in 5 minutes, so we always get a new one.
            let loginData = {
                username: notification.teltonikaUsername,
                password: notification.teltonikaPassword,
            };

            let loginResp = await axios.post(loginUrl, loginData, axiosConfig);