@Subscribe public void onConnectivityChanged(final ConnectivityChangedEvent e) { Connectivity connectivity = model.getConnectivity(); if (!e.isConnected()) { connectivity.setInternet(false); Events.sync(SyncPath.CONNECTIVITY_INTERNET, false); return; } InetAddress ip = e.getNewIp(); connectivity.setIp(ip.getHostAddress()); connectivity.setInternet(true); Events.sync(SyncPath.CONNECTIVITY, model.getConnectivity()); Settings set = model.getSettings(); if (set.getMode() == null || set.getMode() == Mode.unknown) { if (censored.isCensored()) { set.setMode(Mode.get); } else { set.setMode(Mode.give); } } else if (set.getMode() == Mode.give && censored.isCensored()) { // want to set the mode to get now so that we don't mistakenly // proxy any more than necessary set.setMode(Mode.get); log.info("Disconnected; setting giveModeForbidden"); Events.syncModal(model, Modal.giveModeForbidden); } }
@Subscribe public void onLocationChanged(final LocationChangedEvent e) { Events.sync(SyncPath.LOCATION, e.getNewLocation()); if (censored.isCountryCodeCensored(e.getNewCountry())) { if (!censored.isCountryCodeCensored(e.getOldCountry())) { // moving from uncensored to censored if (model.getSettings().getMode() == Mode.give) { Events.syncModal(model, Modal.giveModeForbidden); } } } }
private void quit() { LOG.debug("quit called."); Events.eventBus().post(new QuitEvent()); // LanternHub.display().dispose(); // this.xmppHandler.disconnect(); System.exit(0); }
/** * Fetches user's e-mail - only public for testing. * * @param allToks OAuth tokens. * @param httpClient The HTTP client. */ public int fetchEmail(final Map<String, String> allToks, final HttpClient httpClient) { final String endpoint = "https://www.googleapis.com/oauth2/v1/userinfo"; final String accessToken = allToks.get("access_token"); final HttpGet get = new HttpGet(endpoint); get.setHeader(HttpHeaders.Names.AUTHORIZATION, "Bearer " + accessToken); try { log.debug("About to execute get!"); final HttpResponse response = httpClient.execute(get); final StatusLine line = response.getStatusLine(); log.debug("Got response status: {}", line); final HttpEntity entity = response.getEntity(); final String body = IOUtils.toString(entity.getContent(), "UTF-8"); EntityUtils.consume(entity); log.debug("GOT RESPONSE BODY FOR EMAIL:\n" + body); final int code = line.getStatusCode(); if (code < 200 || code > 299) { log.error("OAuth error?\n" + line); return code; } final Profile profile = JsonUtils.OBJECT_MAPPER.readValue(body, Profile.class); this.model.setProfile(profile); Events.sync(SyncPath.PROFILE, profile); // final String email = profile.getEmail(); // this.model.getSettings().setEmail(email); return code; } catch (final IOException e) { log.warn("Could not connect to Google?", e); } finally { get.reset(); } return -1; }
private void handleReset() { // This posts the reset event to any classes that need to take action, // avoiding coupling this class to those classes. Events.eventBus().post(new ResetEvent()); if (LanternClientConstants.DEFAULT_MODEL_FILE.isFile()) { try { FileUtils.forceDelete(LanternClientConstants.DEFAULT_MODEL_FILE); } catch (final IOException e) { log.warn("Could not delete model file?"); } } final Model base = new Model(model.getCountryService()); model.setEverGetMode(false); model.setLaunchd(base.isLaunchd()); model.setModal(base.getModal()); model.setNodeId(base.getNodeId()); model.setProfile(base.getProfile()); model.setNproxiedSitesMax(base.getNproxiedSitesMax()); // we need to keep clientID and clientSecret, because they are application-level settings String clientID = model.getSettings().getClientID(); String clientSecret = model.getSettings().getClientSecret(); model.setSettings(base.getSettings()); model.getSettings().setClientID(clientID); model.getSettings().setClientSecret(clientSecret); model.setSetupComplete(base.isSetupComplete()); model.setShowVis(base.isShowVis()); // model.setFriends(base.getFriends()); model.clearNotifications(); modelIo.write(); }
@Inject public DefaultPeerFactory( final GeoIpLookupService geoIpLookupService, final Model model, final Roster roster) { this.geoIpLookupService = geoIpLookupService; this.model = model; this.roster = roster; Events.register(this); }
private void connectToGoogleTalk(final Map<String, String> allToks) { final String accessToken = allToks.get("access_token"); final String refreshToken = allToks.get("refresh_token"); if (StringUtils.isBlank(accessToken) || StringUtils.isBlank(refreshToken)) { log.warn("Not access or refresh token -- not logging in!!"); return; } else { // Treat this the same as a credential exception? I.e. what // happens if the user cancels? } this.model.getSettings().setAccessToken(accessToken); this.model.getSettings().setRefreshToken(refreshToken); this.model.getSettings().setUseGoogleOAuth2(true); this.modelIo.write(); Events.asyncEventBus().post(new RefreshTokenEvent(refreshToken)); // We kick this off on another thread, as otherwise it would be // a Jetty thread, and we're about to kill the server. When the // server is killed, the connecting thread would otherwise be // interrupted. final Thread t = new Thread( new Runnable() { @Override public void run() { try { xmppHandler.connect(); log.debug("Setting gtalk authorized"); model.getConnectivity().setGtalkAuthorized(true); internalState.setNotInvited(false); internalState.setModalCompleted(Modal.authorize); internalState.advanceModal(null); } catch (final CredentialException e) { log.error("Could not log in with OAUTH?", e); Events.syncModal(model, Modal.authorize); } catch (final NotInClosedBetaException e) { log.info("This user is not invited"); internalState.setNotInvited(true); Events.syncModal(model, Modal.notInvited); } catch (final IOException e) { log.info("We can't connect (internet connection died?). Retry.", e); Events.syncModal(model, Modal.authorize); } } }, "Google-Talk-Connect-From-Oauth-Servlet-Thread"); t.setDaemon(true); t.start(); }
public void invite(Friend friend) { String email = friend.getEmail(); try { if (xmppHandler.sendInvite(friend, false)) { // we need to mark this email as pending, in case // our invite gets lost. model.addPendingInvite(email); } } catch (Exception e) { log.debug("failed to send invite: ", e); model.addPendingInvite(email); } Events.sync(SyncPath.FRIENDS, model.getFriends().getFriends()); }
@Inject public InteractionServlet( final Model model, final ModelService modelService, final InternalState internalState, final ModelIo modelIo, final Censored censored, final LanternFeedback lanternFeedback, final FriendsHandler friender) { this.model = model; this.modelService = modelService; this.internalState = internalState; this.modelIo = modelIo; this.censored = censored; this.lanternFeedback = lanternFeedback; this.friender = friender; Events.register(this); }
private boolean handleClose(String json) { if (StringUtils.isBlank(json)) { return false; } final ObjectMapper om = new ObjectMapper(); Map<String, Object> map; try { map = om.readValue(json, Map.class); final String notification = (String) map.get("notification"); model.closeNotification(Integer.parseInt(notification)); Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications()); return true; } catch (JsonParseException e) { log.warn("Exception closing notifications {}", e); } catch (JsonMappingException e) { log.warn("Exception closing notifications {}", e); } catch (IOException e) { log.warn("Exception closing notifications {}", e); } return false; }
private boolean handleExceptionalInteractions( final Modal modal, final Interaction inter, final String json) { boolean handled = false; Map<String, Object> map; Boolean notify; switch (inter) { case EXCEPTION: handleException(json); handled = true; break; case UNEXPECTEDSTATERESET: log.debug("Handling unexpected state reset."); backupSettings(); handleReset(); Events.syncModel(this.model); // fall through because this should be done in both cases: case UNEXPECTEDSTATEREFRESH: try { map = jsonToMap(json); } catch (Exception e) { log.error("Bad json payload in inter '{}': {}", inter, json); return true; } notify = (Boolean) map.get("notify"); if (notify) { try { lanternFeedback.submit((String) map.get("report"), this.model.getProfile().getEmail()); } catch (Exception e) { log.error( "Could not submit unexpected state report: {}\n {}", e.getMessage(), (String) map.get("report")); } } handled = true; break; } return handled; }
public void loadOAuth2UserCredentialsFile(final String filename, final Settings set) { if (StringUtils.isBlank(filename)) { log.error("No filename specified"); throw new NullPointerException("No filename specified!"); } final File file = new File(filename); if (!(file.exists() && file.canRead())) { log.error("Unable to read user credentials from {}", filename); throw new IllegalArgumentException("File does not exist! " + filename); } log.info("Reading user credentials from file \"{}\"", filename); try { final String json = FileUtils.readFileToString(file, "US-ASCII"); final JSONObject obj = (JSONObject) JSONValue.parse(json); final String username = (String) obj.get("username"); final String accessToken = (String) obj.get("access_token"); final String refreshToken = (String) obj.get("refresh_token"); // Access token is not strictly necessary, so we allow it to be // null. if (StringUtils.isBlank(username) || StringUtils.isBlank(refreshToken)) { log.error("Failed to parse user credentials file \"{}\"", filename); throw new Error("Could not load username or refresh_token"); } else { set.setAccessToken(accessToken); set.setRefreshToken(refreshToken); set.setUseGoogleOAuth2(true); // We have to be careful here because classes simply haven't // registered as listeners at this point, so listeners have // to make sure to also check for an existing refresh token // in the settings. Events.asyncEventBus().post(new RefreshTokenEvent(refreshToken)); } } catch (final IOException e) { log.error("Failed to read file \"{}\"", filename); throw new Error("Could not load oauth credentials", e); } }
public void setSystemProxy(final boolean systemProxy) { log.info("Setting system proxy..."); this.systemProxy = systemProxy; Events.inOrderAsyncEventBus().post(new SystemProxyChangedEvent(systemProxy)); }
/** * We need to make sure to set the server port before anything is injected -- otherwise we run the * risk of running on a completely different port than what is passed on the command line! * * @param cmd The command line. * @param read The model */ private void processCommandLine(final CommandLine cmd, final Model model) { if (cmd == null) { // Can be true for testing. log.error("No command line?"); return; } final Settings set = model.getSettings(); if (cmd.hasOption(Cli.OPTION_SERVER_PORT)) { final String serverPortStr = cmd.getOptionValue(Cli.OPTION_SERVER_PORT); log.debug("Using command-line proxy port: " + serverPortStr); final int serverPort = Integer.parseInt(serverPortStr); set.setServerPort(serverPort); } else { final int existing = set.getServerPort(); if (existing < 1024) { log.debug("Using random give mode proxy port..."); set.setServerPort(LanternUtils.randomPort()); } } log.info("Running give mode proxy on port: {}", set.getServerPort()); if (cmd.hasOption(Cli.OPTION_KEYSTORE)) { LanternUtils.setFallbackKeystorePath(cmd.getOptionValue(Cli.OPTION_KEYSTORE)); } final String ctrlOpt = Cli.OPTION_CONTROLLER_ID; if (cmd.hasOption(ctrlOpt)) { LanternClientConstants.setControllerId(cmd.getOptionValue(ctrlOpt)); } final String insOpt = Cli.OPTION_INSTANCE_ID; if (cmd.hasOption(insOpt)) { model.setInstanceId(cmd.getOptionValue(insOpt)); } final String fbOpt = Cli.OPTION_AS_FALLBACK; if (cmd.hasOption(fbOpt)) { LanternUtils.setFallbackProxy(true); } final String secOpt = Cli.OPTION_OAUTH2_CLIENT_SECRETS_FILE; if (cmd.hasOption(secOpt)) { loadOAuth2ClientSecretsFile(cmd.getOptionValue(secOpt), set); } final String credOpt = Cli.OPTION_OAUTH2_USER_CREDENTIALS_FILE; if (cmd.hasOption(credOpt)) { loadOAuth2UserCredentialsFile(cmd.getOptionValue(credOpt), set); } final String ripOpt = Cli.OPTION_REPORT_IP; if (cmd.hasOption(ripOpt)) { model.setReportIp(cmd.getOptionValue(ripOpt)); } // final Settings set = LanternHub.settings(); set.setUseTrustedPeers(parseOptionDefaultTrue(cmd, Cli.OPTION_TRUSTED_PEERS)); set.setUseAnonymousPeers(parseOptionDefaultTrue(cmd, Cli.OPTION_ANON_PEERS)); set.setUseLaeProxies(parseOptionDefaultTrue(cmd, Cli.OPTION_LAE)); set.setUseCentralProxies(parseOptionDefaultTrue(cmd, Cli.OPTION_CENTRAL)); set.setUdpProxyPriority( cmd.getOptionValue(Cli.OPTION_UDP_PROXY_PRIORITY, "lower").toUpperCase()); final boolean tcp = parseOptionDefaultTrue(cmd, Cli.OPTION_TCP); final boolean udp = parseOptionDefaultTrue(cmd, Cli.OPTION_UDP); IceConfig.setTcp(tcp); IceConfig.setUdp(udp); set.setTcp(tcp); set.setUdp(udp); /* if (cmd.hasOption(OPTION_USER)) { set.setUserId(cmd.getOptionValue(OPTION_USER)); } if (cmd.hasOption(OPTION_PASS)) { set.(cmd.getOptionValue(OPTION_PASS)); } */ if (cmd.hasOption(Cli.OPTION_ACCESS_TOK)) { set.setAccessToken(cmd.getOptionValue(Cli.OPTION_ACCESS_TOK)); } if (cmd.hasOption(Cli.OPTION_REFRESH_TOK)) { final String refresh = cmd.getOptionValue(Cli.OPTION_REFRESH_TOK); set.setRefreshToken(refresh); Events.asyncEventBus().post(new RefreshTokenEvent(refresh)); } // option to disable use of keychains in local privacy if (cmd.hasOption(Cli.OPTION_DISABLE_KEYCHAIN)) { log.info("Disabling use of system keychains"); set.setKeychainEnabled(false); } else { set.setKeychainEnabled(true); } if (cmd.hasOption(Cli.OPTION_PASSWORD_FILE)) { loadLocalPasswordFile(cmd.getOptionValue(Cli.OPTION_PASSWORD_FILE)); } if (cmd.hasOption(Cli.OPTION_PUBLIC_API)) { set.setBindToLocalhost(false); } log.info("Running API on port: {}", StaticSettings.getApiPort()); if (cmd.hasOption(Cli.OPTION_LAUNCHD)) { log.debug("Running from launchd or launchd set on command line"); model.setLaunchd(true); } else { model.setLaunchd(false); } if (cmd.hasOption(Cli.OPTION_GIVE)) { model.getSettings().setMode(Mode.give); } else if (cmd.hasOption(Cli.OPTION_GET)) { model.getSettings().setMode(Mode.get); } }
public static void sync(final SyncPath path, final Object value) { Events.asyncEventBus().post(new SyncEvent(path, value)); }
public static void syncRosterEntry(final LanternRosterEntry entry, final int index) { final String path = SyncPath.ROSTER.getPath() + "." + index; LOG.debug("Syncing roster entry at path {} with entry {}", path, entry); Events.eventBus().post(new SyncEvent(path, entry)); }
/** Convenience method for syncing the current modal with the frontend. */ public static void syncRoster(final Roster roster) { // This is done synchronously because we need the roster array on the // frontend to be in sync with the backend in order to index into it // on roster updates. Events.eventBus().post(new SyncEvent(SyncPath.ROSTER, roster.getEntries())); }
/** * Convenience method for syncing the current modal with the frontend. * * @param model The state model. */ public static void syncModal(final Model model) { Events.asyncEventBus().post(new SyncEvent(SyncPath.MODAL, model.getModal())); }
@Override public void createTray() { /*uniqueApp = libunique.unique_app_new("org.lantern.lantern", null); if (libunique.unique_app_is_running(uniqueApp)) { LOG.error("Already running!"); System.exit(0); // could signal to open dashboard }*/ menu = libgtk.gtk_menu_new(); connectionStatusItem = libgtk.gtk_menu_item_new_with_label(LABEL_DISCONNECTED); libgtk.gtk_widget_set_sensitive(connectionStatusItem, Gtk.FALSE); libgtk.gtk_menu_shell_append(menu, connectionStatusItem); libgtk.gtk_widget_show_all(connectionStatusItem); dashboardItem = libgtk.gtk_menu_item_new_with_label("Open Dashboard"); dashboardItemCallback = new Gobject.GCallback() { @Override public void callback(Pointer instance, Pointer data) { LOG.debug("openDashboardItem callback called"); openDashboard(); } }; libgobject.g_signal_connect_data( dashboardItem, "activate", dashboardItemCallback, null, null, 0); libgtk.gtk_menu_shell_append(menu, dashboardItem); libgtk.gtk_widget_show_all(dashboardItem); // updateItem = Gtk.gtk_menu_item_new_with_label(); quitItem = libgtk.gtk_menu_item_new_with_label("Quit"); quitItemCallback = new Gobject.GCallback() { @Override public void callback(Pointer instance, Pointer data) { LOG.debug("quitItemCallback called"); quit(); } }; libgobject.g_signal_connect_data(quitItem, "activate", quitItemCallback, null, null, 0); libgtk.gtk_menu_shell_append(menu, quitItem); libgtk.gtk_widget_show_all(quitItem); appIndicator = libappindicator.app_indicator_new( "lantern", "indicator-messages-new", AppIndicator.CATEGORY_APPLICATION_STATUS); /* XXX basically a hack -- we should subclass the AppIndicator type and override the fallback entry in the 'vtable', instead we just hack the app indicator class itself. Not an issue unless we need other appindicators. */ AppIndicator.AppIndicatorClassStruct aiclass = new AppIndicator.AppIndicatorClassStruct(appIndicator.parent.g_type_instance.g_class); AppIndicator.Fallback replacementFallback = new AppIndicator.Fallback() { @Override public Pointer callback(final AppIndicator.AppIndicatorInstanceStruct self) { fallback(); return null; } }; aiclass.fallback = replacementFallback; aiclass.write(); libappindicator.app_indicator_set_menu(appIndicator, menu); changeIcon(ICON_DISCONNECTED, LABEL_DISCONNECTED); libappindicator.app_indicator_set_status(appIndicator, AppIndicator.STATUS_ACTIVE); Events.register(this); this.active = true; }
@Inject public InviteQueue(final XmppHandler handler, final Model model) { this.xmppHandler = handler; this.model = model; Events.register(this); }
public DefaultXmppHandlerTest() { SASLAuthentication.registerSASLMechanism("X-OAUTH2", LanternSaslGoogleOAuth2Mechanism.class); Events.register(this); }
protected void processRequest(final HttpServletRequest req, final HttpServletResponse resp) { LanternUtils.addCSPHeader(resp); final String uri = req.getRequestURI(); log.debug("Received URI: {}", uri); final String interactionStr = StringUtils.substringAfterLast(uri, "/"); if (StringUtils.isBlank(interactionStr)) { log.debug("blank interaction"); HttpUtils.sendClientError(resp, "blank interaction"); return; } log.debug("Headers: " + HttpUtils.getRequestHeaders(req)); if (!"XMLHttpRequest".equals(req.getHeader("X-Requested-With"))) { log.debug("invalid X-Requested-With"); HttpUtils.sendClientError(resp, "invalid X-Requested-With"); return; } if (!SecurityUtils.constantTimeEquals(model.getXsrfToken(), req.getHeader("X-XSRF-TOKEN"))) { log.debug( "X-XSRF-TOKEN wrong: got {} expected {}", req.getHeader("X-XSRF-TOKEN"), model.getXsrfToken()); HttpUtils.sendClientError(resp, "invalid X-XSRF-TOKEN"); return; } final int cl = req.getContentLength(); String json = ""; if (cl > 0) { try { json = IOUtils.toString(req.getInputStream()); } catch (final IOException e) { log.error("Could not parse json?"); } } log.debug("Body: '" + json + "'"); final Interaction inter = Interaction.valueOf(interactionStr.toUpperCase()); if (inter == Interaction.CLOSE) { if (handleClose(json)) { return; } } if (inter == Interaction.URL) { final String url = JsonUtils.getValueFromJson("url", json); if (!StringUtils.startsWith(url, "http://") && !StringUtils.startsWith(url, "https://")) { log.error("http(s) url expected, got {}", url); HttpUtils.sendClientError(resp, "http(s) urls only"); return; } try { new URL(url); } catch (MalformedURLException e) { log.error("invalid url: {}", url); HttpUtils.sendClientError(resp, "invalid url"); return; } final String cmd; if (SystemUtils.IS_OS_MAC_OSX) { cmd = "open"; } else if (SystemUtils.IS_OS_LINUX) { cmd = "gnome-open"; } else if (SystemUtils.IS_OS_WINDOWS) { cmd = "start"; } else { log.error("unsupported OS"); HttpUtils.sendClientError(resp, "unsupported OS"); return; } try { if (SystemUtils.IS_OS_WINDOWS) { // On Windows, we have to quote the url to allow for // e.g. ? and & characters in query string params. // To quote the url, we supply a dummy first argument, // since otherwise start treats the first argument as a // title for the new console window when it's quoted. LanternUtils.runCommand(cmd, "\"\"", "\"" + url + "\""); } else { // on OS X and Linux, special characters in the url make // it through this call without our having to quote them. LanternUtils.runCommand(cmd, url); } } catch (IOException e) { log.error("open url failed"); HttpUtils.sendClientError(resp, "open url failed"); return; } return; } final Modal modal = this.model.getModal(); log.debug( "processRequest: modal = {}, inter = {}, mode = {}", modal, inter, this.model.getSettings().getMode()); if (handleExceptionalInteractions(modal, inter, json)) { return; } Modal switchTo = null; try { // XXX a map would make this more robust switchTo = Modal.valueOf(interactionStr); } catch (IllegalArgumentException e) { } if (switchTo != null && switchModals.contains(switchTo)) { if (!switchTo.equals(modal)) { if (!switchModals.contains(modal)) { this.internalState.setLastModal(modal); } Events.syncModal(model, switchTo); } return; } switch (modal) { case welcome: this.model.getSettings().setMode(Mode.unknown); switch (inter) { case GET: log.debug("Setting get mode"); handleSetModeWelcome(Mode.get); break; case GIVE: log.debug("Setting give mode"); handleSetModeWelcome(Mode.give); break; } break; case authorize: log.debug("Processing authorize modal..."); this.internalState.setModalCompleted(Modal.authorize); this.internalState.advanceModal(null); break; case finished: this.internalState.setCompletedTo(Modal.finished); switch (inter) { case CONTINUE: log.debug("Processing continue"); this.model.setShowVis(true); Events.sync(SyncPath.SHOWVIS, true); this.internalState.setModalCompleted(Modal.finished); this.internalState.advanceModal(null); break; case SET: log.debug("Processing set in finished modal...applying JSON\n{}", json); applyJson(json); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError( resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter); break; } break; case firstInviteReceived: log.error("Processing invite received..."); break; case lanternFriends: this.internalState.setCompletedTo(Modal.lanternFriends); switch (inter) { case FRIEND: this.friender.addFriend(email(json)); break; case REJECT: this.friender.removeFriend(email(json)); break; case CONTINUE: // This dialog always passes continue as of this writing and // not close. case CLOSE: log.debug("Processing continue/close for friends dialog"); if (this.model.isSetupComplete()) { Events.syncModal(model, Modal.none); } else { this.internalState.setModalCompleted(Modal.lanternFriends); this.internalState.advanceModal(null); } break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError( resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter); break; } break; case none: break; case notInvited: switch (inter) { case RETRY: Events.syncModal(model, Modal.authorize); break; // not currently implemented: // case REQUESTINVITE: // Events.syncModal(model, Modal.requestInvite); // break; default: log.error("Unexpected interaction: " + inter); break; } break; case proxiedSites: this.internalState.setCompletedTo(Modal.proxiedSites); switch (inter) { case CONTINUE: if (this.model.isSetupComplete()) { Events.syncModal(model, Modal.none); } else { this.internalState.setModalCompleted(Modal.proxiedSites); this.internalState.advanceModal(null); } break; case LANTERNFRIENDS: log.debug("Processing lanternFriends from proxiedSites"); Events.syncModal(model, Modal.lanternFriends); break; case SET: if (!model.getSettings().isSystemProxy()) { String msg = "Because you are using manual proxy " + "configuration, you may have to restart your " + "browser for your updated proxied sites list " + "to take effect."; model.addNotification(msg, MessageType.info, 30); Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications()); } applyJson(json); break; case SETTINGS: log.debug("Processing settings from proxiedSites"); Events.syncModal(model, Modal.settings); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError(resp, "unexpected interaction for proxied sites"); break; } break; case requestInvite: log.info("Processing request invite"); switch (inter) { case CANCEL: this.internalState.setModalCompleted(Modal.requestInvite); this.internalState.advanceModal(Modal.notInvited); break; case CONTINUE: applyJson(json); this.internalState.setModalCompleted(Modal.proxiedSites); // TODO: need to do something here this.internalState.advanceModal(null); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError(resp, "unexpected interaction for request invite"); break; } break; case requestSent: log.debug("Process request sent"); break; case settings: switch (inter) { case GET: log.debug("Setting get mode"); // Only deal with a mode change if the mode has changed! if (modelService.getMode() == Mode.give) { // Break this out because it's set in the subsequent // setMode call final boolean everGet = model.isEverGetMode(); this.modelService.setMode(Mode.get); if (!everGet) { // need to do more setup to switch to get mode from // give mode model.setSetupComplete(false); model.setModal(Modal.proxiedSites); Events.syncModel(model); } else { // This primarily just triggers a setup complete event, // which triggers connecting to proxies, setting up // the local system proxy, etc. model.setSetupComplete(true); } } break; case GIVE: log.debug("Setting give mode"); this.modelService.setMode(Mode.give); break; case CLOSE: log.debug("Processing settings close"); Events.syncModal(model, Modal.none); break; case SET: log.debug("Processing set in setting...applying JSON\n{}", json); applyJson(json); break; case RESET: log.debug("Processing reset"); Events.syncModal(model, Modal.confirmReset); break; case PROXIEDSITES: log.debug("Processing proxied sites in settings"); Events.syncModal(model, Modal.proxiedSites); break; case LANTERNFRIENDS: log.debug("Processing friends in settings"); Events.syncModal(model, Modal.lanternFriends); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError( resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter); break; } break; case settingsLoadFailure: switch (inter) { case RETRY: modelIo.reload(); Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications()); Events.syncModal(model, model.getModal()); break; case RESET: backupSettings(); Events.syncModal(model, Modal.welcome); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); break; } break; case systemProxy: this.internalState.setCompletedTo(Modal.systemProxy); switch (inter) { case CONTINUE: log.debug("Processing continue in systemProxy", json); applyJson(json); Events.sync(SyncPath.SYSTEMPROXY, model.getSettings().isSystemProxy()); this.internalState.setModalCompleted(Modal.systemProxy); this.internalState.advanceModal(null); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError(resp, "error setting system proxy pref"); break; } break; case updateAvailable: switch (inter) { case CLOSE: this.internalState.setModalCompleted(Modal.updateAvailable); this.internalState.advanceModal(null); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); break; } break; case authorizeLater: log.error("Did not handle interaction {} for modal {}", inter, modal); break; case confirmReset: log.debug("Handling confirm reset interaction"); switch (inter) { case CANCEL: log.debug("Processing cancel"); Events.syncModal(model, Modal.settings); break; case RESET: handleReset(); Events.syncModel(this.model); break; default: log.error("Did not handle interaction {} for modal {}", inter, modal); HttpUtils.sendClientError( resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter); } break; case about: // fall through on purpose case sponsor: switch (inter) { case CLOSE: Events.syncModal(model, this.internalState.getLastModal()); break; default: HttpUtils.sendClientError(resp, "invalid interaction " + inter); } break; case contact: switch (inter) { case CONTINUE: String msg; MessageType messageType; try { lanternFeedback.submit(json, this.model.getProfile().getEmail()); msg = "Thank you for contacting Lantern."; messageType = MessageType.info; } catch (Exception e) { log.error("Error submitting contact form: {}", e); msg = "Error sending message. Please check your " + "connection and try again."; messageType = MessageType.error; } model.addNotification(msg, messageType, 30); Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications()); // fall through because this should be done in both cases: case CANCEL: Events.syncModal(model, this.internalState.getLastModal()); break; default: HttpUtils.sendClientError(resp, "invalid interaction " + inter); } break; case giveModeForbidden: if (inter == Interaction.CONTINUE) { // need to do more setup to switch to get mode from give mode model.getSettings().setMode(Mode.get); model.setSetupComplete(false); this.internalState.advanceModal(null); Events.syncModal(model, Modal.proxiedSites); Events.sync(SyncPath.SETUPCOMPLETE, false); } break; default: log.error("No matching modal for {}", modal); } this.modelIo.write(); }
private void handleSetModeWelcome(final Mode mode) { this.model.setModal(Modal.authorize); this.internalState.setModalCompleted(Modal.welcome); this.modelService.setMode(mode); Events.syncModal(model); }