Commit Graph

559 Commits

Author SHA1 Message Date
Scott Lamb
004aa5d6ce extend "moonfire-nvr sql" to pass args to sqlite3 2019-06-19 21:15:25 -07:00
Scott Lamb
a6ebf2d10d add "sql" subcommand
This delegates to the "sqlite3" CLI but has a couple benefits over using
sqlite3 directly:

  * safer because it does the same locking as other moonfire-nvr invocations
  * more convenient because it takes the same argument format as other
    moonfire-nvr subcommands:
      * --db-dir rather than full path including /db suffix
      * has the --db-dir default value
      * --read-only rather than file:...?mode=ro

Use like "moonfire-nvr sql" or "moonfire-nvr sql --read-only".
2019-06-19 17:20:44 -07:00
Scott Lamb
80306064a3 add missing build.rs 2019-06-19 16:53:14 -07:00
Scott Lamb
a5ffe3ca2c bump minimum Rust version
The master version of rust-protobuf requires the TryFrom feature,
stabilized in 1.34.
2019-06-19 15:56:04 -07:00
Scott Lamb
fda7e4ca2b add concept of user/session permissions
(I also considered the names "capabilities" and "scopes", but I think
"permissions" is the most widely understood.)

This is increasingly necessary as the web API becomes more capable.
Among other things, it allows:

* non-administrator users who can view but not access camera passwords
  or change any state
* workers that update signal state based on cameras' built-in motion
  detection or a security system's events but don't need to view videos
* control over what can be done without authenticating

Currently session permissions are just copied from user permissions, but
you can also imagine admin sessions vs not, as a checkbox when signing
in. This would match the standard Unix workflow of using a
non-administrative session most of the time.

Relevant to my current signals work (#28) and to the addition of an
administrative API (#35, including #66).
2019-06-19 15:34:20 -07:00
Scott Lamb
d8b8d5d5e0 fix dumb typo bug in signal/state input validation
The effect was that it'd allow any state for signal 0, when it should
have allowed state 0 for any signal.
2019-06-14 16:41:18 -07:00
Scott Lamb
1312349ca1 stop using deprecated libc::int64_t
The cool kids just use i64 now.
2019-06-14 16:14:07 -07:00
Scott Lamb
6d4b06f7d2 web api glue for updating signals
This is very lightly tested, but it at least sometimes works.
2019-06-14 16:11:12 -07:00
Scott Lamb
7fe9d34655 cargo fix --all
* it added "dyn" to trait objects
* it changed "..." in patterns to "..="

cargo --version says: "cargo 1.37.0-nightly (545f35425 2019-05-23)"
2019-06-14 08:47:11 -07:00
Scott Lamb
7dd98bb76a db crate support for updating signals (#28)
This is a definite work in progress. In particular,

* there's no src/web.rs support yet so it can't be used,
* the code is surprisingly complex, and there's almost no tests so far.
  I want to at least get complete branch coverage.
* I may still go back to time_sec rather than time_90k to save RAM and
  flash.

I simplified the approach a bit from the earlier goal in design/api.md.
In particular, there's no longer the separate concept of "observation"
vs "prediction". Now the predictions are just observations that extend a
bit beyond now. They may be flushed prematurely and I'll try living with
that to avoid making things even more complex.
2019-06-13 22:25:55 -07:00
Scott Lamb
d232ca55fa document proposed API for updating signals (#28) 2019-06-07 10:19:38 -07:00
Scott Lamb
6f2c63ffac read-only signals support (#28)
This is mostly untested and useless by itself, but it's a starting
point. In particular:

* there's no way to set up signals or add/remove/update events yet
  except by manual changes to the database.
* if you associate a signal with a camera then remove the camera,
  hitting /api/ will error out.
2019-06-06 16:20:44 -07:00
Scott Lamb
cb1bb5d810 upgrade cursive to latest major version 2019-05-31 16:35:07 -07:00
Scott Lamb
225e1fd75b upgrade db's parking_lot dependency too 2019-05-31 16:21:10 -07:00
Scott Lamb
b629fe6ac1 upgrade rusqlite, bump required Rust to 1.33
The new rusqlite requires the transpose_result feature, stabilized in
this Rust version.
2019-05-31 16:19:04 -07:00
Scott Lamb
3668c69d4b bump required Rust version to 1.32
travis-ci pointed out that the dependency bump broke 1.31:

   Compiling docopt v1.1.0
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
   --> /home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/docopt-1.1.0/src/parse.rs:48:5
    |
48  |   use regex;
    |       ^^^^^
    |

Looks like uniform_paths was stabilized in 1.32, and I verified locally that
version builds.
2019-05-31 16:09:42 -07:00
Scott Lamb
428f5a3ba4 update a few deps
cursive & rusqlite are more significant; I'll do those separately
2019-05-31 15:08:49 -07:00
Scott Lamb
6f0c8c19de honor removing a time constraint
Looks like a bug got introduced with the great UI rewrite: when you add
a (start or end) time constraint, then remove one, the change wouldn't
be reflected. Within CalendarTSRange, it used null to mean to keep a
value, and || to check if it was null. These meant empty strings turned
into the existing value, instead of no constraint as they should be.
This was unnecessarily clever; stop doing that.

Also keep the console logging in the deployed config; it's harmless and
eases debugging.
2019-02-19 13:42:26 -08:00
Scott Lamb
36f3bda9c6 update deps 2019-02-13 22:43:30 -08:00
Scott Lamb
579150c9d5 redact URLs within stream.rs; fixes #13 2019-02-13 22:34:19 -08:00
Scott Lamb
d7a0cb9a7c Remove mention of #36 from troubleshooting guide
The 091217b workaround of telling ffmpeg to only request the video
stream works perfectly fine for now. I'll revisit when adding audio
support (#34).

Fixes #36
2019-02-13 22:25:33 -08:00
Scott Lamb
091217b1a4 configure ffmpeg to only stream video
This works around #36 for now. I'll need to do something different when
I actually implement audio support.
2019-02-11 22:58:09 -08:00
Scott Lamb
c271cfa2b5 make Writer enforce maximum recording duration
My installation recently somehow ended up with a recording with a
duration of 503793844 90,000ths of a second, way over the maximum of 5
minutes. (Looks like the machine was pretty unresponsive at the time
and/or having network problems.)

When this happens, the system really spirals. Every flush afterward (12
per minute with my installation) fails with a CHECK constraint failure
on the recording table. It never gives up on that recording. /var/log
fills pretty quickly as this failure is extremely verbose (a stack
trace, and a line for each byte of video_index). Eventually the sample
file dirs fill up too as it continues writing video samples while GC is
stuck. The video samples are useless anyway; given that they're not
referenced in the database, they'll be deleted on next startup.

This ensures the offending recording is never added to the database, so
we don't get the same persistent problem. Instead, writing to the
recording will fail. The stream will drop and be retried. If the
underlying condition that caused a too-long recording (many
non-key-frames, or the camera returning a crazy duration, or the
monotonic clock jumping forward extremely, or something) has gone away,
the system should recover.
2019-01-29 08:26:36 -08:00
Scott Lamb
3ba3bf2b18 backend support for live stream (#59)
This is so far completely untested, for use by a new UI prototype.

It creates a new URL endpoint which sends one video/mp4 media segment
per key frame, with the dependent frames included. This means there will
be about one key frame interval of latency (typically about a second).
This seems hard to avoid, as mentioned in issue #59.
2019-01-21 15:58:52 -08:00
Scott Lamb
95a8c2e78d support .mp4 files > 13.25 hours
Use version 1 of the mvhd, tkhd, and mdhd boxes to support 64-bit
durations. 2^32 units / 90,000 units/sec / 60 sec/min / 60 min/hr ~=
13.25 hrs.

Compatibility: looks like Chrome, Firefox, VLC, and ffmepg all support
version 1 with no problem.
2019-01-07 00:59:32 -08:00
Scott Lamb
b9e6a6461f fix streamer tests broken by 4cc796f
That commit rewrote the db/writer.rs tests. But the flush op they
used before was also used by src/streamer.rs tests. Reintroduce it.
2019-01-06 07:07:04 -08:00
Scott Lamb
4cc796f697 properly test fix for #64
I went with the third idea in 1ce52e3: have the tests run each iteration
of the syncer explicitly. These are messy tests that know tons of
internal details, but I think they're less confusing and racy than if I
had the syncer running in a separate thread.
2019-01-04 16:11:58 -08:00
Scott Lamb
1ce52e334c fix #64 (extraneous flushes)
Now each syncer has a binary heap of the times it plans to do a flush.
When one of those times arrives, it rechecks if there's something to do.
Seems more straightforward than rechecking each stream's first
uncommitted recording, especially with the logic to retry failed flushes
every minute.

Also improved the info! log for each flush to see the actual recordings
being flushed for better debuggability.

No new tests right now. :-( They're tricky to write. One problem is that
it's hard to get the timing right: a different flush has to happen
after Syncer::save's database operations and before Syncer::run calls
SimulatedClocks::recv_timeout with an empty channel[*], advancing the
time. I've thought of a few ways of doing this:

   * adding a new SyncerCommand to run something, but it's messy (have
     to add it from the mock of one of the actions done by the save),
     and Box<dyn FnOnce() + 'static> not working (see
     rust-lang/rust#28796) makes it especially annoying.

   * replacing SimulatedClocks with something more like MockClocks.
     Lots of boilerplate. Maybe I need to find a good general-purpose
     Rust mock library. (mockers sounds good but I want something that
     works on stable Rust.)

   * bypassing the Syncer::run loop, instead manually running iterations
     from the test.

Maybe the last way is the best for now. I'm likely to try it soon.

[*] actually, it's calling Receiver::recv_timeout directly;
Clocks::recv_timeout is dead code now? oops.
2019-01-04 13:47:44 -08:00
Scott Lamb
55fa458288 fix confusing variable name + comment 2019-01-04 06:16:25 -08:00
Scott Lamb
de643f9f8d include segments in debug output 2018-12-29 13:15:01 -06:00
Scott Lamb
eb8a51aecb add a url for getting debug info about a .mp4 file
and add a unit test of path decoding along the way
2018-12-29 13:09:16 -06:00
Scott Lamb
1123adec5d try upgrading travis-ci setup to xenial
This no longer requires installing ffmpeg manually, so there should be
significantly less data to cache (faster runs). The build step itself
should also be faster when the cache is unavailable/stale.

Also sneak in a change from "pkg-config" to "pkgconf" package in the
scripts and travis CI. They didn't match the manual instructions; make
them all consistent. They both seem to work fine, but I gather pkgconf
is the newer thing. Its roadmap is here and notes that distros are
moving toward it.

https://github.com/pkgconf/pkgconf/wiki/Roadmap
2018-12-29 12:21:57 -06:00
Scott Lamb
b5387af3d4 lose "extern crate" everywhere (Rust 2018 edition) 2018-12-28 21:59:39 -06:00
Scott Lamb
f5703b9968 introduce typed errors and use in mp4 code
Fixes #46. If there are no video_sample_entries, it returns
InvalidArgument, which gets mapped to a HTTP 400. Various other failures
turn into non-500s as well.

There are many places that can & should be using typed errors, but it's
a start.
2018-12-28 17:30:33 -06:00
Scott Lamb
0b0f4ec9ed NLL-inspired simplifications to db.rs
* remove intermediate bool from adjust_day.

* rewrite LockedDatabase::list_aggregate_recordings.
  I started by collapsing the flush into the first part of the if, in a
  similar way to adjust_day. But then I refactored more and ended up
  with a structure that probably would have been allowed with the old
  lexical borrow checker. I think it's more readable, and it does 1
  btree operation per row where before it did 2 or 3.
2018-12-28 15:10:12 -06:00
Scott Lamb
699ec87968 upgrade to 2018 Rust edition
This is mostly just "cargo fix --edition" + Cargo.toml changes.
There's one fix for upgrading to NLL in db/writer.rs:
Writer::previously_opened wouldn't build with NLL because of a
double-borrow the previous borrow checker somehow didn't catch.
Restructure to avoid it.

I'll put elective NLL changes in a following commit.
2018-12-28 14:59:06 -06:00
Scott Lamb
ff58f24785 update deps 2018-12-28 10:13:03 -06:00
Scott Lamb
3644548018 fix some outdated comments in slices.rs 2018-12-28 10:04:47 -06:00
Scott Lamb
89fa35a2f7 be slightly more graceful on bad /view.mp4 (#46)
Before, this would panic from the reactor thread. After, it returns a
internal server error. Still not ideal, but better.

To return "bad request" as it should, mp4::FileBuilder::build() should
return a new error type that distinguishes "invalid argument" from
"internal" and the like. I'm thinking of using a ErrorKind enum
throughout the program that's similar to grpc::StatusCode.
2018-12-28 09:01:47 -06:00
Scott Lamb
4580038013 fix --require-auth flag
Apparently with docopt, --require-auth=false doesn't work, so booleans
with a default value of true can't be turned off. Toggle the default to
false to deal with this, for now. I'd prefer the default be true, but
I also would prefer to not use a negative --no-require-auth or
--allow-unauthenticated flag. I think I'll switch from docopt to clap
in the near future; it seems to be what the cool kids use.
2018-12-28 08:39:50 -06:00
Scott Lamb
54ebc6ec2f install the tzdata package from scripts
Fixes #53
2018-12-27 16:34:35 -06:00
Scott Lamb
278a87d5fd tweaks to guide/secure.md
after reading the rendered version online
2018-12-27 16:29:26 -06:00
Scott Lamb
24674f5b50 document proxy setup in guide/secure.md (for #26)
The guide is not as quick to follow and amateur-friendly as I'd like. A
few things that might improve matters:

   * complete #27 (built-in https+letsencrypt), so that when not sharing
     the port, users don't need to use nginx or certbot.
   * more ubiquitous IPv6 (out of my control but should happen over
     time) to reduce need to share the port
   * embed a dynamic DNS client
   * support UPnP Internet Gateway Device Control Protocol (if common
     routers have this enabled? probably not for security reasons.)

It's progress, though. Enough that I think I'll merge the auth branch
into master shortly.
2018-12-27 16:00:15 -06:00
Scott Lamb
3c1163dfe2 use SameSite=Strict (for #26)
I initially chose SameSite=Lax because I thought if a user followed a
link to the landing page, the landing page's ajax requests wouldn't send
the cookie. But I just did an experiment, and that's not true. Only the
initial page load (of a .html file) lacks the cookie. All of its
resources and ajax requests send the cookie. I'm not sure about
document.cookie accesses, but my cookie is HttpOnly anyway, so it's
irrelevant. So no reason to be lax.
2018-12-01 22:04:54 -08:00
Scott Lamb
3f76096a81 add Cache-Control: private hdr to non-static stuff
for #26
2018-12-01 16:55:10 -08:00
Scott Lamb
4f87c16c31 Merge branch 'master' into auth 2018-12-01 15:27:54 -08:00
Scott Lamb
35e6891221 update all Rust deps 2018-12-01 15:20:19 -08:00
Scott Lamb
087fdafc61 endpoint to debug --trust-forward-hdrs for #26 2018-12-01 00:44:19 -08:00
Scott Lamb
d35a4592e3 Merge branch 'master' into auth 2018-12-01 00:06:43 -08:00
Scott Lamb
b2bdccb507 Javascript fix for unauthenticated case
newTimeFormat didn't handle newTimeZone not having been called well.
Restore the prior behavior of having called newTimeZone(null), which was
apparently good enough.
2018-12-01 00:04:43 -08:00