Skip to content
Merged

Release #2300

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
2cb719d
feat: Add check to skip localhost instances in OpenSourceDeploymentAPI
nawazdhandala Feb 12, 2026
10d0068
Refactor code structure for improved readability and maintainability
nawazdhandala Feb 12, 2026
3a51496
Refactor UI components to enhance styling and shadows
nawazdhandala Feb 12, 2026
2b64dd0
Refactor Settings, Login, and Server URL screens to use Tailwind CSS …
nawazdhandala Feb 12, 2026
9699830
feat: Add babel-preset-expo to dependencies for improved Babel config…
nawazdhandala Feb 12, 2026
86fda9b
refactor: Update Tailwind CSS configuration and clean up imports; rem…
nawazdhandala Feb 12, 2026
cc23416
refactor: Move SafeAreaProvider to wrap the PersistQueryClientProvide…
nawazdhandala Feb 12, 2026
749bd2e
refactor: Replace react-native-keychain with AsyncStorage for token m…
nawazdhandala Feb 12, 2026
e5f652a
refactor: Remove Notification Preferences screen and related navigati…
nawazdhandala Feb 12, 2026
ec56609
refactor: Update biometric labels for clarity in SettingsScreen
nawazdhandala Feb 12, 2026
01c6101
Refactor navigation and screens for incidents and alerts
nawazdhandala Feb 12, 2026
b1c9d9a
refactor: Add Ionicons for tab bar icons in MainTabNavigator
nawazdhandala Feb 12, 2026
d5613cc
refactor: Integrate Ionicons for improved iconography in EmptyState, …
nawazdhandala Feb 12, 2026
87475b0
Enhance UI components and improve accessibility across multiple screens
nawazdhandala Feb 12, 2026
c7ca613
chore: npm audit fix
simlarsen Feb 13, 2026
43fc5ac
Refactor HomeScreen to consolidate project counts using useAllProject…
nawazdhandala Feb 13, 2026
fd3f75e
refactor: Consolidate API fetching logic for alerts, incidents, and e…
nawazdhandala Feb 13, 2026
4a4dff9
refactor: Add 'muted' prop to AlertCard, EpisodeCard, and IncidentCar…
nawazdhandala Feb 13, 2026
bf3d908
refactor: Add feed fetching functions and integrate FeedTimeline comp…
nawazdhandala Feb 13, 2026
aa40129
refactor: Update SettingsRow component to consolidate version display…
nawazdhandala Feb 13, 2026
5ca85e4
refactor: Update header comment in fetchProjects function for clarity…
nawazdhandala Feb 13, 2026
fd89989
Merge pull request #2297 from OneUptime/chore/npm-audit-fix
simlarsen Feb 13, 2026
049c5d0
refactor: Add flex styling to SectionList in AlertsScreen and Inciden…
nawazdhandala Feb 13, 2026
cfba736
refactor: Update loading state to use 'isPending' instead of 'isLoadi…
nawazdhandala Feb 13, 2026
aefc649
refactor: Integrate useAuth in ProjectProvider for authentication han…
nawazdhandala Feb 13, 2026
6751d59
refactor: Remove totalActive calculation and active issues summary fr…
nawazdhandala Feb 13, 2026
f2a2644
Merge branch 'release'
nawazdhandala Feb 13, 2026
6a90ee9
Merge branch 'master' of https://github.com/OneUptime/oneuptime
nawazdhandala Feb 13, 2026
d0d26d2
refactor: Integrate SplashScreen to hide native splash screen after l…
nawazdhandala Feb 13, 2026
196e9ca
refactor: Enhance error handling in getBlogPost method to return null…
nawazdhandala Feb 13, 2026
dafa0cc
refactor: Update styling in AppContent and RootNavigator for consiste…
nawazdhandala Feb 13, 2026
770ef00
refactor: Enhance response normalization in API client to handle seri…
nawazdhandala Feb 13, 2026
f6a8cef
feat: Add DNS monitoring capabilities
nawazdhandala Feb 13, 2026
f324a4e
feat: Implement DNS monitoring configuration and secret handling
nawazdhandala Feb 13, 2026
f3cd7be
refactor: Clean up code formatting and improve readability across mul…
nawazdhandala Feb 13, 2026
2897a93
Merge pull request #2298 from OneUptime/refactor-mob-app
simlarsen Feb 13, 2026
c9bc214
fix: Correct CAA record resolution method and typo in value formatting
nawazdhandala Feb 13, 2026
fcc6223
refactor: Remove unused variables and improve type annotations in hoo…
nawazdhandala Feb 13, 2026
8b2f9bc
Merge pull request #2299 from OneUptime/dna-monitor
simlarsen Feb 13, 2026
46a9f95
fix: Update error handling in getUserMiddleware to use NotAuthenticat…
nawazdhandala Feb 13, 2026
dec03bc
feat: Add expo-font dependency to package.json and package-lock.json
nawazdhandala Feb 13, 2026
00d4148
Enhance UI and UX across multiple screens
nawazdhandala Feb 13, 2026
8040dd0
Refactor UI components and enhance styling
nawazdhandala Feb 13, 2026
109c276
feat: Update GlassCard component to support opaque prop and apply it …
nawazdhandala Feb 13, 2026
86edee3
style: Update color scheme and improve UI consistency across components
nawazdhandala Feb 13, 2026
fc9026a
refactor: Clean up component code and improve formatting across multi…
nawazdhandala Feb 13, 2026
8b42af3
refactor: Remove unused noteModalVisible prop from NotesSection compo…
nawazdhandala Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions APIReference/Service/DataTypeDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,19 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
},
],
},
{
name: "dnsMonitor",
type: "MonitorStepDnsMonitor",
required: false,
description:
"Configuration for DNS monitoring. Required for DNS monitor type. Defines query name (domain), record type, optional DNS server, port, timeout, and retry settings. See MonitorStepDnsMonitor.",
typeLinks: [
{
label: "MonitorStepDnsMonitor",
path: "monitor-step-dns-monitor",
},
],
},
],
values: [],
jsonExample: JSON.stringify(
Expand Down Expand Up @@ -2560,6 +2573,31 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
description:
"Whether the SNMP device is reachable. Use with 'True' or 'False'. Applies to: SNMP monitors.",
},
{
value: "DNS Response Time (in ms)",
description:
"The DNS query response time in milliseconds. Use with numeric FilterTypes. Applies to: DNS monitors.",
},
{
value: "DNS Is Online",
description:
"Whether the DNS resolution succeeded. Use with 'True' or 'False'. Applies to: DNS monitors.",
},
{
value: "DNS Record Value",
description:
"The value of a DNS record returned by the query. Use with string FilterTypes (Contains, EqualTo, etc.). Applies to: DNS monitors.",
},
{
value: "DNSSEC Is Valid",
description:
"Whether DNSSEC validation passed (AD flag present). Use with 'True' or 'False'. Applies to: DNS monitors.",
},
{
value: "DNS Record Exists",
description:
"Whether any DNS records were returned for the query. Use with 'True' or 'False'. Applies to: DNS monitors.",
},
{
value: "JavaScript Expression",
description:
Expand Down Expand Up @@ -3112,6 +3150,93 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
2,
),
},
"monitor-step-dns-monitor": {
title: "MonitorStepDnsMonitor",
description:
"Configuration for a DNS monitor step. Defines the domain to query, record type, optional custom DNS server, and timeout settings. Used as the 'dnsMonitor' property on a MonitorStep when the monitor type is 'DNS'. The criteria filters can then use 'DNS Is Online', 'DNS Response Time (in ms)', 'DNS Record Value', 'DNSSEC Is Valid', and 'DNS Record Exists' as CheckOn values.",
isEnum: false,
relatedTypes: [
{
name: "MonitorStep",
path: "monitor-step",
relationship: "Parent that holds this as dnsMonitor property",
},
{
name: "CheckOn",
path: "check-on",
relationship: "Use DNS-specific CheckOn values with DNS monitors",
},
],
properties: [
{
name: "queryName",
type: "string",
required: true,
description: "The domain name to query (e.g., 'example.com').",
},
{
name: "recordType",
type: "string (enum)",
required: true,
description:
"The DNS record type to query. Possible values: 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SOA', 'PTR', 'SRV', 'CAA'.",
},
{
name: "hostname",
type: "string",
required: false,
description:
"Custom DNS server to use for the query (e.g., '8.8.8.8'). Leave empty to use system default DNS resolver.",
},
{
name: "port",
type: "number",
required: false,
description: "DNS port. Default is 53.",
},
{
name: "timeout",
type: "number",
required: false,
description:
"Timeout for DNS queries in milliseconds. Default is 5000 (5 seconds).",
},
{
name: "retries",
type: "number",
required: false,
description: "Number of retries for failed DNS queries. Default is 3.",
},
],
values: [],
jsonExample: JSON.stringify(
{
"// Example 1: Basic A record lookup": {
queryName: "example.com",
recordType: "A",
timeout: 5000,
retries: 3,
},
"// Example 2: MX record with custom DNS server": {
queryName: "example.com",
recordType: "MX",
hostname: "8.8.8.8",
port: 53,
timeout: 5000,
retries: 3,
},
"// Example 3: TXT record for SPF verification": {
queryName: "example.com",
recordType: "TXT",
hostname: "1.1.1.1",
timeout: 5000,
retries: 3,
},
},
null,
2,
),
},
};

export default class ServiceHandler {
Expand Down
6 changes: 3 additions & 3 deletions App/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Common/Server/API/OpenSourceDeploymentAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ export default class OpenSourceDeploymentAPI extends BaseAPI<
(body["oneuptimeVersion"] as string) || "unknown";
deployment.instanceUrl = (body["instanceUrl"] as string) || "";

// Skip localhost instances - these are default/unconfigured deployments.
if (
deployment.instanceUrl === "http://localhost/" ||
deployment.instanceUrl === "http://localhost"
) {
return Response.sendEmptySuccessResponse(req, res);
}

await OpenSourceDeploymentService.create({
data: deployment,
props: {
Expand Down
11 changes: 8 additions & 3 deletions Common/Server/Middleware/UserAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,15 @@ export default class UserMiddleware {
try {
oneuptimeRequest.userAuthorization = JSONWebToken.decode(accessToken);
} catch (err) {
// if the token is invalid or expired, it'll throw this error.
// if the token is invalid or expired, return 401 so clients can refresh the token.
logger.error(err);
oneuptimeRequest.userType = UserType.Public;
return next();
return Response.sendErrorResponse(
req,
res,
new NotAuthenticatedException(
"AccessToken is invalid or expired. Please refresh your token.",
),
);
}

if (oneuptimeRequest.userAuthorization.isMasterAdmin) {
Expand Down
8 changes: 8 additions & 0 deletions Common/Server/Services/MonitorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ export class Service extends DatabaseService<Model> {
monitorDestination = `${monitorDestination}:${port}`;
}
}

// For DNS monitors, use the queryName from dnsMonitor config
if (monitorType === MonitorType.DNS && firstStep?.data?.dnsMonitor) {
monitorDestination = firstStep.data.dnsMonitor.queryName || "";
if (firstStep.data.dnsMonitor.hostname) {
monitorDestination = `${monitorDestination} @${firstStep.data.dnsMonitor.hostname}`;
}
}
}
}

Expand Down
183 changes: 183 additions & 0 deletions Common/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import DataToProcess from "../DataToProcess";
import CompareCriteria from "./CompareCriteria";
import {
CheckOn,
CriteriaFilter,
FilterType,
} from "../../../../Types/Monitor/CriteriaFilter";
import DnsMonitorResponse from "../../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
import EvaluateOverTime from "./EvaluateOverTime";
import CaptureSpan from "../../Telemetry/CaptureSpan";
import logger from "../../Logger";

export default class DnsMonitorCriteria {
@CaptureSpan()
public static async isMonitorInstanceCriteriaFilterMet(input: {
dataToProcess: DataToProcess;
criteriaFilter: CriteriaFilter;
}): Promise<string | null> {
let threshold: number | string | undefined | null =
input.criteriaFilter.value;

const dataToProcess: ProbeMonitorResponse =
input.dataToProcess as ProbeMonitorResponse;

const dnsResponse: DnsMonitorResponse | undefined =
dataToProcess.dnsResponse;

let overTimeValue: Array<number | boolean> | number | boolean | undefined =
undefined;

if (
input.criteriaFilter.evaluateOverTime &&
input.criteriaFilter.evaluateOverTimeOptions
) {
try {
overTimeValue = await EvaluateOverTime.getValueOverTime({
projectId: (input.dataToProcess as ProbeMonitorResponse).projectId,
monitorId: input.dataToProcess.monitorId!,
evaluateOverTimeOptions: input.criteriaFilter.evaluateOverTimeOptions,
metricType: input.criteriaFilter.checkOn,
});

if (Array.isArray(overTimeValue) && overTimeValue.length === 0) {
overTimeValue = undefined;
}
} catch (err) {
logger.error(
`Error in getting over time value for ${input.criteriaFilter.checkOn}`,
);
logger.error(err);
overTimeValue = undefined;
}
}

// Check if DNS is online
if (input.criteriaFilter.checkOn === CheckOn.DnsIsOnline) {
const currentIsOnline: boolean | Array<boolean> =
(overTimeValue as Array<boolean>) ||
(input.dataToProcess as ProbeMonitorResponse).isOnline;

return CompareCriteria.compareCriteriaBoolean({
value: currentIsOnline,
criteriaFilter: input.criteriaFilter,
});
}

// Check DNS response time
if (input.criteriaFilter.checkOn === CheckOn.DnsResponseTime) {
threshold = CompareCriteria.convertToNumber(threshold);

if (threshold === null || threshold === undefined) {
return null;
}

const currentResponseTime: number | Array<number> =
(overTimeValue as Array<number>) ||
dnsResponse?.responseTimeInMs ||
(input.dataToProcess as ProbeMonitorResponse).responseTimeInMs;

if (currentResponseTime === null || currentResponseTime === undefined) {
return null;
}

return CompareCriteria.compareCriteriaNumbers({
value: currentResponseTime,
threshold: threshold as number,
criteriaFilter: input.criteriaFilter,
});
}

// Check if DNS record exists
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordExists) {
const exists: boolean = Boolean(
dnsResponse?.records && dnsResponse.records.length > 0,
);

const isTrue: boolean =
input.criteriaFilter.filterType === FilterType.True;
const isFalse: boolean =
input.criteriaFilter.filterType === FilterType.False;

if (exists && isTrue) {
return `DNS records exist for the query.`;
}

if (!exists && isFalse) {
return `No DNS records found for the query.`;
}

return null;
}

// Check DNSSEC validity
if (input.criteriaFilter.checkOn === CheckOn.DnssecIsValid) {
const isTrue: boolean =
input.criteriaFilter.filterType === FilterType.True;
const isFalse: boolean =
input.criteriaFilter.filterType === FilterType.False;

if (dnsResponse?.isDnssecValid === undefined) {
return null;
}

if (dnsResponse.isDnssecValid && isTrue) {
return `DNSSEC is valid.`;
}

if (!dnsResponse.isDnssecValid && isFalse) {
return `DNSSEC is not valid.`;
}

return null;
}

// Check DNS record value
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordValue) {
if (!dnsResponse?.records || dnsResponse.records.length === 0) {
return null;
}

// Check if any record value matches the criteria
for (const record of dnsResponse.records) {
const recordValue: string = record.value;

// Try numeric comparison first
if (
typeof threshold === "number" ||
(typeof threshold === "string" && !isNaN(Number(threshold)))
) {
const numericThreshold: number | null =
CompareCriteria.convertToNumber(threshold);

if (numericThreshold !== null && !isNaN(Number(recordValue))) {
const result: string | null =
CompareCriteria.compareCriteriaNumbers({
value: Number(recordValue),
threshold: numericThreshold,
criteriaFilter: input.criteriaFilter,
});

if (result) {
return `DNS record (${record.type}): ${result}`;
}
}
}

// String comparison
const result: string | null = CompareCriteria.compareCriteriaStrings({
value: recordValue,
threshold: String(threshold),
criteriaFilter: input.criteriaFilter,
});

if (result) {
return `DNS record (${record.type}): ${result}`;
}
}
}

return null;
}
}
Loading
Loading