Repository: louislam/uptime-kuma
File: server/model/heartbeat.js (JavaScript)

Code before:
     * @returns {object} Object ready to parse
     */
    toPublicJSON() {
        return {
            status: this.status,
            time: this.time,
            msg: "", // Hide for public
            ping: this.ping,
        };
    }

    /**
     * Return an object that ready to parse to JSON
     * @returns {object} Object ready to parse
     */
    toJSON() {
        return {
            monitorID: this._monitorId,
            status: this._status,
            time: this._time,
            msg: this._msg,
            ping: this._ping,
            important: this._important,
            duration: this._duration,
            retries: this._retries,
            response: Heartbeat.decodeResponseValue(this._response),
        };
    }

    /**
     * Decode compressed response payload stored in database.
     * @param {string|null} response Encoded response payload.
     * @returns {string|null} Decoded response payload.
     */
    static decodeResponseValue(response) {
        if (!response) {
            return response;
        }

        try {
            return zlib.gunzipSync(Buffer.from(response, "base64")).toString("utf8");
        } catch (error) {
            return response;
        }
    }
}

module.exports = Heartbeat;


Review comment (suggestion):
Since frontends can decode gzip natively, I think decoding this before the notification is handed off to the notification providers (=not here) makes sense.

-> in toJson(), we should either include `this._response`, or preferably add a `includeResponse=false` flag, since this still can be multi-GB large (we did not restrict this).

Code after:
     * Return an object that ready to parse to JSON for public
     * Only show necessary data to public
     * @returns {object} Object ready to parse
     */
    toPublicJSON() {
        return {
            status: this.status,
            time: this.time,
            msg: "", // Hide for public
            ping: this.ping,
        };
    }

    /**
     * Return an object that ready to parse to JSON
     * @returns {object} Object ready to parse
     */
    toJSON() {
        return {
            monitorID: this._monitorId,
            status: this._status,
            time: this._time,
            msg: this._msg,
            ping: this._ping,
            important: this._important,
            duration: this._duration,
            retries: this._retries,
            response: this._response,
        };
    }

    /**
     * Return an object that ready to parse to JSON
     * @param {{ decodeResponse?: boolean }} opts Options for JSON serialization
     * @returns {Promise<object>} Object ready to parse
     */
    async toJSONAsync(opts) {
        return {
            monitorID: this._monitorId,
            status: this._status,
            time: this._time,
            msg: this._msg,
            ping: this._ping,
            important: this._important,
            duration: this._duration,
            retries: this._retries,
            response: opts?.decodeResponse ? await Heartbeat.decodeResponseValue(this._response) : undefined,
        };
    }

    /**