Use signed rlog URLs for shared rides (#20)

main
Andy 2019-09-16 13:38:41 -04:00 committed by Chris Vickery
parent 811cb2cc53
commit 87b77f3a57
8 changed files with 81 additions and 62 deletions

View File

@ -4,7 +4,7 @@
"private": true,
"homepage": "https://community.comma.ai/cabana",
"dependencies": {
"@commaai/comma-api": "^1.1.4",
"@commaai/comma-api": "1.1.6",
"@commaai/hls.js": "^0.12.2",
"@commaai/log_reader": "^0.3.1",
"@commaai/my-comma-auth": "^1.1.0",

View File

@ -6,7 +6,12 @@ import { createWriteStream } from "streamsaver";
import Panda from "@commaai/pandajs";
import CommaAuth from "@commaai/my-comma-auth";
import { raw as RawDataApi, drives as DrivesApi } from "@commaai/comma-api";
import { USE_UNLOGGER, PART_SEGMENT_LENGTH, STREAMING_WINDOW } from "./config";
import {
USE_UNLOGGER,
PART_SEGMENT_LENGTH,
STREAMING_WINDOW,
GITHUB_AUTH_TOKEN_KEY
} from "./config";
import * as GithubAuth from "./api/github-auth";
import DBC from "./models/can/dbc";
@ -27,6 +32,7 @@ import OpenDbc from "./api/OpenDbc";
import UnloggerClient from "./api/unlogger";
import * as ObjectUtils from "./utils/object";
import { hash } from "./utils/string";
import { modifyQueryParameters } from "./utils/url";
const RLogDownloader = require("./workers/rlog-downloader.worker.js");
const LogCSVDownloader = require("./workers/dbc-csv-downloader.worker.js");
@ -80,7 +86,9 @@ export default class CanExplorer extends Component {
pandaNoDeviceSelected: false,
live: false,
isGithubAuthenticated:
props.githubAuthToken !== null && props.githubAuthToken !== undefined
props.githubAuthToken !== null && props.githubAuthToken !== undefined,
shareUrl: null,
logUrls: null
};
this.openDbcClient = new OpenDbc(props.githubAuthToken);
@ -126,9 +134,13 @@ export default class CanExplorer extends Component {
componentWillMount() {
const { dongleId, name } = this.props;
if (CommaAuth.isAuthenticated() && !name) {
// TODO link to explorer
this.showOnboarding();
} else if (this.props.max && this.props.url) {
} else if (
this.props.max &&
this.props.url &&
!this.props.exp &&
!this.props.sig
) {
// probably the demo!
const { max, url } = this.props;
const startTime = Moment(name, "YYYY-MM-DD--H-m-s");
@ -148,7 +160,8 @@ export default class CanExplorer extends Component {
);
} else if (dongleId && name) {
const routeName = dongleId + "|" + name;
let urlPromise;
let urlPromise, logUrlsPromise;
if (this.props.url) {
urlPromise = Promise.resolve(this.props.url);
} else {
@ -156,7 +169,16 @@ export default class CanExplorer extends Component {
return route.url;
});
}
Promise.all([urlPromise, RawDataApi.getLogUrls(routeName)])
if (this.props.sig && this.props.exp) {
logUrlsPromise = RawDataApi.getLogUrls(routeName, {
sig: this.props.sig,
exp: this.props.exp
});
} else {
logUrlsPromise = RawDataApi.getLogUrls(routeName);
}
Promise.all([urlPromise, logUrlsPromise])
.then(initData => {
let [url, logUrls] = initData;
const newState = {
@ -169,9 +191,24 @@ export default class CanExplorer extends Component {
currentParts: [
0,
Math.min(logUrls.length - 1, PART_SEGMENT_LENGTH - 1)
]
],
logUrls
};
this.setState(newState, this.initCanData);
DrivesApi.getShareSignature(routeName).then(shareSignature =>
this.setState({
shareUrl: modifyQueryParameters({
add: {
exp: shareSignature.exp,
sig: shareSignature.sig,
max: logUrls.length - 1,
url
},
remove: [GITHUB_AUTH_TOKEN_KEY]
})
})
);
})
.catch(err => {
console.error(err);
@ -519,7 +556,8 @@ export default class CanExplorer extends Component {
// so that we don't try to read metadata about it...
isDemo: this.props.isDemo,
isShare: this.props.isShare,
isLegacyShare: this.props.isLegacyShare,
logUrls: this.state.logUrls,
// data that is used
dbcText: dbc.text(),
@ -974,6 +1012,7 @@ export default class CanExplorer extends Component {
route={this.state.route}
seekTime={this.state.seekTime}
seekIndex={this.state.seekIndex}
shareUrl={this.state.shareUrl}
maxByteStateChangeCount={this.state.maxByteStateChangeCount}
isDemo={this.props.isDemo}
live={this.state.live}

View File

@ -15,28 +15,9 @@ function ensureInit() {
return initPromise;
}
export async function getLogURLList(routeName) {
if (urlStore[routeName]) {
return urlStore[routeName];
}
await ensureInit();
var data = await RawDataApi.getLogUrls(routeName);
urlStore[routeName] = data;
setTimeout(function() {
delete urlStore[routeName];
}, 1000 * 60 * 45); // expires in 1h, lets reset in 45m
return urlStore[routeName];
}
export async function getLogPart(routeName, part) {
export async function getLogPart(logUrl) {
return new Promise(async function(resolve, reject) {
var logUrls = await getLogURLList(routeName);
request(logUrls[part], function(err, res) {
request(logUrl, function(err, res) {
if (err) {
return reject(err);
}

View File

@ -3,9 +3,7 @@ import cx from "classnames";
import PropTypes from "prop-types";
import Clipboard from "clipboard";
import { modifyQueryParameters } from "../utils/url";
import MessageBytes from "./MessageBytes";
import { GITHUB_AUTH_TOKEN_KEY } from "../config";
const { ckmeans } = require("simple-statistics");
export default class Meta extends Component {
@ -340,17 +338,6 @@ export default class Meta extends Component {
);
}
shareUrl() {
const add = {
max: this.props.route.proclog,
url: this.props.route.url
};
const remove = [GITHUB_AUTH_TOKEN_KEY]; // don't share github access
const shareUrl = modifyQueryParameters({ add, remove });
return shareUrl;
}
saveable() {
try {
// eslint-disable-next-line
@ -386,16 +373,16 @@ export default class Meta extends Component {
<button onClick={this.props.saveLog}>Save Log</button>
</div>
)}
{this.props.route ? (
{this.props.shareUrl ? (
<div
className="cabana-meta-header-action special-wide"
data-clipboard-text={this.shareUrl()}
data-clipboard-text={this.props.shareUrl}
data-clipboard-action="copy"
ref={ref => (ref ? new Clipboard(ref) : null)}
>
<a
className="button"
href={this.shareUrl()}
href={this.props.shareUrl}
onClick={e => e.preventDefault()}
>
Copy Share Link

View File

@ -29,14 +29,24 @@ if (routeFullName) {
persistedDbc = fetchPersistedDbc(routeFullName);
let max = getUrlParameter("max"),
url = getUrlParameter("url");
url = getUrlParameter("url"),
exp = getUrlParameter("exp"),
sig = getUrlParameter("sig");
if (max) {
props.max = Number(max);
}
if (url) {
props.url = url;
}
props.isShare = max && url;
if (exp) {
props.exp = exp;
}
if (sig) {
props.sig = sig;
}
props.isLegacyShare = max && url && !exp && !sig;
props.isShare = max && url && exp && sig;
} else if (getUrlParameter("demo")) {
props.max = 12;
props.url =

View File

@ -16,7 +16,7 @@ export function getUrlParameter(name) {
: decodeURIComponent(results[1].replace(/\+/g, " "));
}
export function modifyQueryParameters({ add, remove }) {
export function modifyQueryParameters({ add, remove = [] }) {
var regex = new RegExp("[\\?&]([^&#]+)=([^&#]*)");
var results = regex.exec(location.search);

View File

@ -2,7 +2,7 @@ import LogStream from "@commaai/log_reader";
import { timeout } from "thyming";
import { partial } from "ap";
import { getLogPart, getLogURLList } from "../api/rlog";
import { getLogPart } from "../api/rlog";
import DbcUtils from "../utils/dbc";
import DBC from "../models/can/dbc";
import { addressForName } from "../models/can/logSignals";
@ -24,12 +24,13 @@ function CacheEntry(options) {
options = options || {};
this.options = options;
let { route, part, dbc } = options;
let { route, part, dbc, logUrls } = options;
this.messages = {};
this.route = route;
this.part = part;
this.dbc = dbc;
this.logUrls = logUrls;
this.sendBatch = partial(sendBatch, this);
// load in the data!
@ -71,9 +72,10 @@ function sendBatch(entry) {
async function loadData(entry) {
var url = null;
if (!entry.options.isDemo && !entry.options.isShare) {
url = (await getLogURLList(entry.route))[entry.part];
if (!entry.options.isDemo && !entry.options.isLegacyShare) {
url = entry.logUrls[entry.part];
}
if (!url || url.indexOf(".7z") !== -1) {
// this is a shit log we can't read...
var data = await loadCanPart(
@ -88,7 +90,7 @@ async function loadData(entry) {
return self.postMessage(data);
}
var res = await getLogPart(entry.route, entry.part);
var res = await getLogPart(entry.logUrls[entry.part]);
var logReader = new LogStream(res);
entry.ended = false;

View File

@ -17,20 +17,20 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@commaai/comma-api@^1.0.0":
version "1.0.12"
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.0.12.tgz#aa2be678dd0cdcf5102602e011051eda354853d6"
integrity sha512-AWwKaQzgQt6oyOP0lvMqy5/7rMQbKIVwTYX5MJnBFOVOgHrGmzxhPk8Bsi+5GpSA1qSFbnzoMvQ95QFC5teJhw==
"@commaai/comma-api@1.1.6":
version "1.1.6"
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.1.6.tgz#be486443a8d8843c74a811cdd406b85694b5d526"
integrity sha512-LWglx5+GiQN4uhdBUjTJ3hsHxy0/tFVwZrIFKLSwwFyclQWizriHOE4IxKkGLudyQ/KgOL+bLljA+z/huEXW4w==
dependencies:
babel-runtime "^6.26.0"
config-request "^0.5.1"
joi-browser "^13.4.0"
querystringify "^2.1.1"
"@commaai/comma-api@^1.1.4":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.1.4.tgz#75f727bfa43f6f446a341d1f9154f15334cfb79e"
integrity sha512-S25QY2OwO1aO5HKtvJQUnCwDsfBhgj7+SANZG99kHvxfFxOwWzT/GcV7G/xEtEJ06OsJ+Ih8XoUFm7IxNc1bwA==
"@commaai/comma-api@^1.0.0":
version "1.0.12"
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.0.12.tgz#aa2be678dd0cdcf5102602e011051eda354853d6"
integrity sha512-AWwKaQzgQt6oyOP0lvMqy5/7rMQbKIVwTYX5MJnBFOVOgHrGmzxhPk8Bsi+5GpSA1qSFbnzoMvQ95QFC5teJhw==
dependencies:
babel-runtime "^6.26.0"
config-request "^0.5.1"