Created
May 15, 2025 11:20
-
-
Save pdaug/4b90013aca360835660f7720f821585c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { IncomingHttpHeaders } from "http"; | |
// types | |
import { RequestExtended } from "../types/Request"; | |
import { TypeUserAgentBrowser, TypeUserAgentDevice, TypeUserAgentSystem } from "../types/Utils"; | |
/** | |
* Class for detecting information about the browser and device from the User-Agent header. | |
* | |
* @class | |
*/ | |
class UserAgent { | |
req: RequestExtended; | |
headers: IncomingHttpHeaders; | |
accept: IncomingHttpHeaders["accept"]; | |
userAgent: IncomingHttpHeaders["user-agent"]; | |
/** | |
* Creates an instance of the `UserAgent` class. | |
* @param {RequestExtended} req - The request object with headers. | |
*/ | |
constructor(req: RequestExtended) { | |
this.req = req; | |
this.headers = req.headers; | |
this.accept = req.headers?.["accept"]?.toLocaleLowerCase(); | |
this.userAgent = req.headers?.["user-agent"]?.toLocaleLowerCase(); | |
return; | |
} | |
/** | |
* Detects the browser based on the `User-Agent` header of the request. | |
* | |
* @returns {TypeUserAgentBrowser} The name of the browser (e.g., "chrome", "firefox", "opera", etc.) | |
*/ | |
browser(): TypeUserAgentBrowser { | |
let currentBrowser: TypeUserAgentBrowser = "unknown"; | |
if (!this.userAgent) { | |
return currentBrowser; | |
} | |
if (/opera|opr/i.test(this.userAgent)) { | |
currentBrowser = "opera"; | |
} else if (/edge|edg/i.test(this.userAgent)) { | |
currentBrowser = "edge"; | |
} else if (/chrome/i.test(this.userAgent)) { | |
currentBrowser = "chrome"; | |
} else if (/firefox/i.test(this.userAgent)) { | |
currentBrowser = "firefox"; | |
} else if (/safari/i.test(this.userAgent)) { | |
currentBrowser = "safari"; | |
} else if (/msie|trident/i.test(this.userAgent)) { | |
currentBrowser = "internet explorer"; | |
} | |
return currentBrowser; | |
} | |
/** | |
* Detects the type of device based on the `User-Agent` header and `Accept` header of the request. | |
* | |
* @returns {TypeUserAgentDevice} The type of the device ("mobile", "api", "desktop"). | |
*/ | |
device(): TypeUserAgentDevice { | |
let currentDevice: TypeUserAgentDevice = "desktop"; | |
if (this.userAgent && /mobile|iphone|android|ipad/.test(this.userAgent)) { | |
currentDevice = "mobile"; | |
} | |
if (this.userAgent && /postmanruntime/.test(this.userAgent)) { | |
currentDevice = "api"; | |
} | |
if (this.userAgent && /curl/.test(this.userAgent)) { | |
currentDevice = "api"; | |
} | |
if ((this.accept && this.accept.includes("application/json")) || !this.userAgent) { | |
currentDevice = "api"; | |
} | |
return currentDevice; | |
} | |
/** | |
* Detects the operating system from the user-agent string. | |
* | |
* @returns {TypeUserAgentSystem} The name of the detected operating system. | |
* Possible return values: 'windows', 'macos', 'android', 'ios', 'linux', or 'unknown' if no match is found. | |
*/ | |
system(): TypeUserAgentSystem { | |
let currentSystem: TypeUserAgentSystem = "unknown"; | |
if (!this.userAgent) { | |
return currentSystem; | |
} | |
if (/windows nt/.test(this.userAgent)) { | |
currentSystem = "windows"; | |
} else if (/iphone|ipad|ipod/.test(this.userAgent)) { | |
currentSystem = "ios"; | |
} else if (/mac os x|macintosh/.test(this.userAgent)) { | |
currentSystem = "macos"; | |
} else if (/android/.test(this.userAgent)) { | |
currentSystem = "android"; | |
} else if (/linux/.test(this.userAgent)) { | |
currentSystem = "linux"; | |
} | |
return currentSystem; | |
} | |
/** | |
* Retrieves the client's IP address from the request headers. | |
* It first checks the 'x-forwarded-for' header, which may contain a list of IPs if the request passed through proxies. | |
* If unavailable, it falls back to the remote address from the socket. | |
* | |
* @returns {string} The client's IP address as a string. | |
*/ | |
ip(): string { | |
const forwardedFor = this.headers?.["x-forwarded-for"]; | |
if (typeof forwardedFor === "string") { | |
return forwardedFor.split(",")[0].trim(); | |
} | |
return this.req.socket?.remoteAddress || ""; | |
} | |
} | |
export default UserAgent; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment