npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

capacitor-time-integrity

v0.1.0

Published

Capacitor plugin that exposes the device monotonic clock so the app can detect wall-clock tampering

Readme

capacitor-time-integrity

Plugin Capacitor yang mengekspos monotonic clock device supaya aplikasi bisa mendeteksi jam kalender (wall clock) yang digeser — kasus utamanya: kecurangan absensi dengan mengubah jam device.

Dibangun untuk Capacitor 8.2.0 (@capacitor/core sebagai peer dependency ^8.2.0).

Kenapa plugin ini ada

iOS tidak menyediakan public API untuk membaca toggle Settings → General → Date & Time → Set Automatically. Yang bisa dilakukan adalah memakai jam kedua yang tidak bisa dimanipulasi user:

| | Wall clock | Monotonic clock | |---|---|---| | API iOS | Date() | CLOCK_MONOTONIC_RAW / mach_continuous_time() | | API Android | System.currentTimeMillis() | SystemClock.elapsedRealtime() | | Makna | tanggal & jam kalender | lama waktu sejak boot | | Bisa di-set user | ya | tidak | | Reset | tidak | saat reboot |

Dengan membandingkan laju keduanya terhadap satu titik acuan, perubahan jam terdeteksi tanpa perlu koneksi ke server.

Catatan penting soal pemilihan API iOS

ProcessInfo.systemUptime, CACurrentMediaTime(), dan mach_absolute_time() berhenti saat device tidur (semantik CLOCK_UPTIME_RAW). Kalau dipakai untuk deteksi ini, setiap iPhone yang di-lock beberapa jam akan menghasilkan drift palsu yang besar. Plugin ini memakai CLOCK_MONOTONIC_RAW, yang terus berjalan saat sleep — sepadan dengan SystemClock.elapsedRealtime() di Android.

Instalasi

Paket ini berada di luar repo aplikasi, sejajar dengan plugin internal lain di ~/project/capacitor/. Aplikasi GreatDay memakainya lewat dependency lokal:

"capacitor-time-integrity": "file:../../capacitor/capacitor-time-integrity"

Penting untuk CI. Path relatif di atas hanya ada di mesin developer. Runner GitLab yang meng-clone repo aplikasi saja akan gagal pada pnpm install. Sebelum merge, publish paket ini ke registry lalu ganti dependency-nya menjadi versi terbit, sama seperti capacitor-plugin-security-check dkk.:

npm publish                                  # dari folder plugin ini
pnpm add [email protected]      # dari repo aplikasi

Setelah mengubah kode native plugin, dari repo aplikasi jalankan:

pnpm install
pnpm exec cap sync        # daftarkan modul Android + pod iOS

cap sync menuliskan:

  • android/capacitor.settings.gradle → include ':capacitor-time-integrity'
  • android/app/capacitor.build.gradle → implementation project(':capacitor-time-integrity')
  • android/app/src/main/assets/capacitor.plugins.json → com.greatday.plugins.timeintegrity.TimeIntegrityPlugin
  • ios/App/Podfile → pod 'CapacitorTimeIntegrity', :path => '../../node_modules/capacitor-time-integrity'
  • ios/App/App/capacitor.config.json → TimeIntegrityPlugin pada packageClassList

Build layer TypeScript (dist/) diperlukan sebelum publish atau bila paket ini diimpor lewat nama paketnya:

npm install               # sekali, untuk devDependencies (tsc, rollup)
npm run build             # tsc + rollup → dist/

API

import { TimeIntegrity } from 'capacitor-time-integrity';

const sample = await TimeIntegrity.getTimeInfo();

getTimeInfo() => Promise<TimeSample>

| Field | Tipe | Keterangan | |---|---|---| | wallMs | number | Wall clock, ms epoch UTC (sama dengan Date.now()) | | continuousMs | number | Monotonic clock, ms sejak boot — tidak bisa di-set user | | bootTimeMs | number | Estimasi wall clock saat boot (iOS: kern.boottime) | | monotonicReliable | boolean | false di web — pemanggil harus menonaktifkan deteksi | | autoTimeSupported | boolean | true hanya di Android | | autoTime | boolean \| null | Settings.Global.AUTO_TIME; null di iOS/web | | autoTimeZone | boolean \| null | Settings.Global.AUTO_TIME_ZONE; null di iOS/web | | platform | string | ios, android, atau web |

Cara pakai: anchor + dua sinyal

Simpan satu titik acuan ketika waktu server masih dipercaya:

const sample = await TimeIntegrity.getTimeInfo();
const anchor = {
  serverMs,                                // waktu dari server
  wallMs: sample.wallMs,
  continuousMs: sample.continuousMs,
  offsetMs: sample.wallMs - serverMs,      // selisih jam device vs server
};

Lalu setiap kali butuh waktu yang tepercaya:

const now = await TimeIntegrity.getTimeInfo();
const elapsed = now.continuousMs - anchor.continuousMs;   // tidak bisa dipalsukan

const trustedNowMs = anchor.serverMs + elapsed;           // valid meski offline
const driftMs = now.wallMs - (anchor.wallMs + elapsed);   // ≠ 0 → jam digeser sejak anchor

Dua sinyal ini harus dipakai berdua, karena masing-masing menutup lubang yang lain:

| Sinyal | Menangkap | Butuh online? | Lubangnya | |---|---|---|---| | offsetMs | jam sudah salah sebelum anchor dibuat | ya (saat anchor dibuat) | tidak melihat perubahan setelah anchor | | driftMs | jam digeser sesudah anchor dibuat | tidak | jadi 0 bila anchor diperbarui setelah jam digeser |

Kelalaian yang mudah terjadi: memperbarui anchor tepat sebelum pemeriksaan (mis. karena waktu server dianggap kedaluwarsa) akan mereset wallMs baseline ke jam yang sudah digeser, sehingga driftMs kembali 0. offsetMs yang dihitung pada saat anchor dibuat tetap merekam manipulasinya.

trustedNowMs inilah yang sebaiknya dipakai sebagai timestamp transaksi, bukan Date.now().

Batasan

  • Reboot menghapus baseline. continuousMs reset ke ~0, jadi anchor lama tidak valid (deteksi: continuousMs sekarang < continuousMs anchor). Perlu sinkronisasi ulang ke server. Mitigasi parsial: simpan waktu tepercaya tertinggi yang pernah dilihat — waktu tidak bisa mundur, jadi wall clock yang lebih kecil dari nilai itu pasti dimanipulasi.
  • Auto-time ON bukan jaminan. Dengan NTP/DNS palsu, jam bisa salah walau autoTime === true. Karena itu drift tetap perlu diperiksa di Android.
  • Web tidak didukung. performance.now() reset per page load dan di-throttle di tab background; monotonicReliable sengaja false.
  • Jailbreak/root bisa mem-hook API monotonic. Kelas ancaman berbeda, ditangani plugin deteksi root/jailbreak terpisah.

Implementasi di aplikasi ini

Layer Angular-nya ada di repo aplikasi GreatDay, src/app/core/services/library/time-integrity/:

  • time-integrity.plugin.ts — bridge registerPlugin('TimeIntegrity') lokal, supaya aplikasi tidak bergantung pada hasil build dist/ paket ini dan otomatis memakai implementasi native setelah cap sync.
  • time-integrity.service.ts — pengelolaan anchor, getTrustedNowMs(), getDriftMs(), getOffsetMs(), dan ratchet waktu maju.

Setelah paket ini dipublish dan terpasang dari registry, time-integrity.plugin.ts bisa diganti dengan import { TimeIntegrity } from 'capacitor-time-integrity' (saat itu dist/ sudah tersedia di dalam tarball paket).