Exemple #1
0
def auth_do(req, service):
    svc = Service.FromID(service)
    from tapiriik.services.api import APIException
    try:
        if svc.RequiresExtendedAuthorizationDetails:
            uid, authData, extendedAuthData = svc.Authorize(
                req.POST["username"], req.POST["password"])
        else:
            uid, authData = svc.Authorize(req.POST["username"],
                                          req.POST["password"])
    except APIException:
        return False
    if authData is not None:
        serviceRecord = Service.EnsureServiceRecordWithAuth(
            svc,
            uid,
            authData,
            extendedAuthDetails=extendedAuthData
            if svc.RequiresExtendedAuthorizationDetails else None,
            persistExtendedAuthDetails=bool(req.POST.get("persist", None)))
        # auth by this service connection
        existingUser = User.AuthByService(serviceRecord)
        # only log us in as this different user in the case that we don't already have an account
        if existingUser is not None and req.user is None:
            User.Login(existingUser, req)
        else:
            User.Ensure(req)
        # link service to user account, possible merge happens behind the scenes (but doesn't effect active user)
        User.ConnectService(req.user, serviceRecord)
        return True
    return False
Exemple #2
0
def payments_claim_return(request, code):
    user, payment = Payments.ConsumeClaimCode(code)
    if not payment:
        return render(request, "payments/claim_return_fail.html")
    User.AssociatePayment(user, payment)
    User.Login(user, request)  # In case they somehow managed to log out - they've proved their identity.
    return redirect("/#/payments/claimed")
Exemple #3
0
def authreturn(req, service, level=None):
    if ("error" in req.GET or "not_approved" in req.GET):
        success = False
    else:
        svc = Service.FromID(service)
        try:
            uid, authData = svc.RetrieveAuthorizationToken(req, level)
        except Exception as e:
            return render(req, "oauth-failure.html", {
                "service": svc,
                "error": str(e)
            })
        serviceRecord = Service.EnsureServiceRecordWithAuth(svc, uid, authData)

        # auth by this service connection
        existingUser = User.AuthByService(serviceRecord)
        # only log us in as this different user in the case that we don't already have an account
        if req.user is None and existingUser is not None:
            User.Login(existingUser, req)
        else:
            User.Ensure(req)
        # link service to user account, possible merge happens behind the scenes (but doesn't effect active user)
        User.ConnectService(req.user, serviceRecord)
        success = True

    return render(req, "oauth-return.html", {"success": 1 if success else 0})
Exemple #4
0
def payments_ipn(req):
    raw_data = req.body.decode("utf-8")
    raw_data += "&cmd=_notify-validate"
    ipnreq = urllib.request.Request(PP_WEBSCR)
    ipnreq.add_header("Content-type", "application/x-www-form-urlencoded")
    result = urllib.request.urlopen(ipnreq, raw_data.encode("utf-8"))
    response = result.read().decode("utf-8")
    if response != "VERIFIED":
        logger.error("IPN request %s not validated - response %s" %
                     (req.body, response))
        return HttpResponse(status=403)
    if req.POST["receiver_id"] != PP_RECEIVER_ID or req.POST[
            "mc_currency"] != PAYMENT_CURRENCY:
        logger.error("IPN request %s has incorrect details" % req.POST)
        return HttpResponse(status=400)
    if req.POST["payment_status"] != "Completed":
        logger.error("IPN request %s not complete" % req.POST)
        return HttpResponse()
    logger.info("IPN request %s OK" % str(req.POST))
    payment = Payments.LogPayment(req.POST["txn_id"],
                                  amount=req.POST["mc_gross"],
                                  initialAssociatedAccount=req.POST["custom"],
                                  email=req.POST["payer_email"])
    user = User.Get(req.POST["custom"])
    User.AssociatePayment(user, payment)
    try:
        ab_experiment_complete("autosync", user["_id"],
                               float(req.POST["mc_gross"]))
    except:
        logger.error("AB experiment did not complete - no experiment running?")
    return HttpResponse()
Exemple #5
0
def payments_ipn(req):
    raw_data = req.body.decode("utf-8")
    raw_data += "&cmd=_notify-validate"
    ipnreq = urllib.request.Request(PP_WEBSCR)
    ipnreq.add_header("Content-type", "application/x-www-form-urlencoded")
    result = urllib.request.urlopen(ipnreq, raw_data.encode("utf-8"))
    response = result.read().decode("utf-8")
    if response != "VERIFIED":
        logger.error("IPN request %s not validated - response %s" %
                     (req.body, response))
        return HttpResponse(status=403)
    if req.POST["receiver_id"] != PP_RECEIVER_ID or req.POST[
            "mc_currency"] != PAYMENT_CURRENCY:
        logger.error("IPN request %s has incorrect details" % req.POST)
        return HttpResponse(status=400)
    if req.POST["payment_status"] == "Refunded":
        Payments.ReversePayment(req.POST["parent_txn_id"])
        logger.info("IPN refund %s OK" % str(req.POST))
        return HttpResponse()
    if req.POST["payment_status"] != "Completed":
        logger.error("IPN request %s not complete" % req.POST)
        return HttpResponse()
    logger.info("IPN request %s OK" % str(req.POST))
    payment = Payments.LogPayment(req.POST["txn_id"],
                                  amount=req.POST["mc_gross"],
                                  initialAssociatedAccount=req.POST["custom"],
                                  email=req.POST["payer_email"])
    user = User.Get(req.POST["custom"])
    User.AssociatePayment(user, payment)

    if "_id" not in payment:  # Is the payment newly entered? Really should have used an ORM about 3 years ago.
        payments_send_confirmation(req, req.POST["payer_email"])
    return HttpResponse()
def js_bridge(req):
    serviceInfo = {}

    for svc in Service.List():
        if svc.ID in WITHDRAWN_SERVICES:
            continue
        if req.user is not None:
            svcRec = User.GetConnectionRecord(
                req.user,
                svc.ID)  # maybe make the auth handler do this only once?
        else:
            svcRec = None
        info = {
            "DisplayName": svc.DisplayName,
            "DisplayAbbreviation": svc.DisplayAbbreviation,
            "AuthenticationType": svc.AuthenticationType,
            "UsesExtendedAuth": svc.RequiresExtendedAuthorizationDetails,
            "AuthorizationURL": svc.UserAuthorizationURL,
            "NoFrame": svc.AuthenticationNoFrame,
            "ReceivesActivities": svc.ReceivesActivities,
            "Configurable": svc.Configurable,
            "RequiresConfiguration": False  # by default
        }
        if svcRec:
            if svc.Configurable:
                if svc.ID == "dropbox":  # dirty hack alert, but better than dumping the auth details in their entirety
                    info["AccessLevel"] = "full" if svcRec.Authorization[
                        "Full"] else "normal"
                    info["RequiresConfiguration"] = svc.RequiresConfiguration(
                        svcRec)
            info["Config"] = svcRec.GetConfiguration()
            info["HasExtendedAuth"] = svcRec.HasExtendedAuthorizationDetails()
            info[
                "PersistedExtendedAuth"] = svcRec.HasExtendedAuthorizationDetails(
                    persisted_only=True)
            info["ExternalID"] = svcRec.ExternalID
        info["BlockFlowTo"] = []
        info["Connected"] = svcRec is not None
        serviceInfo[svc.ID] = info
    if req.user is not None:
        flowExc = User.GetFlowExceptions(req.user)
        for exc in flowExc:
            if exc["Source"]["Service"] not in serviceInfo or exc["Target"][
                    "Service"] not in serviceInfo:
                continue  # Withdrawn services
            if "ExternalID" in serviceInfo[exc["Source"][
                    "Service"]] and exc["Source"]["ExternalID"] != serviceInfo[
                        exc["Source"]["Service"]]["ExternalID"]:
                continue  # this is an old exception for a different connection
            if "ExternalID" in serviceInfo[exc["Target"][
                    "Service"]] and exc["Target"]["ExternalID"] != serviceInfo[
                        exc["Target"]["Service"]]["ExternalID"]:
                continue  # same as above
            serviceInfo[exc["Source"]["Service"]]["BlockFlowTo"].append(
                exc["Target"]["Service"])
    return {"js_bridge_serviceinfo": json.dumps(serviceInfo)}
Exemple #7
0
def sync_status_rc(req):
    token = req.GET.get('token')

    if token is None:
        return HttpResponse(status=403)

    user = User.EnsureWithRcToken(req, token)
    uid, authData, extendedAuthData = (token, {}, {"token": token})
    serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, uid, authData, extendedAuthData, True)
    User.ConnectService(user, serviceRecord)

    return sync_status(req)
Exemple #8
0
def auth_rc(req):
    token = req.GET.get('token')

    if token is None:
        return redirect("https://app.runnersconnect.net")

    user = User.EnsureWithRcToken(req, token)
    uid, authData, extendedAuthData = (token, {}, {"token": token})
    serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, uid, authData, extendedAuthData, True)
    User.ConnectService(user, serviceRecord)

    return render(req, "dashboard.html")
Exemple #9
0
def config_flow_save(req, service):
    if not req.user:
        return HttpResponse(status=403)
    conns = User.GetConnectionRecordsByUser(req.user)
    if service not in [x.Service.ID for x in conns]:
        return HttpResponse(status=404)
    sourceSvc = [x for x in conns if x.Service.ID == service][0]
    #  the JS doesn't resolve the flow exceptions, it just passes in the expanded config flags for the edited service (which will override other flowexceptions)
    flowFlags = json.loads(req.POST["flowFlags"])
    for destSvc in [x for x in conns if x.Service.ID != service]:
        User.SetFlowException(req.user, sourceSvc, destSvc, destSvc.Service.ID in flowFlags["forward"], None)
    Sync.SetNextSyncIsExhaustive(req.user, True)  # to pick up any activities left behind
    return HttpResponse()
Exemple #10
0
def auth_do(req, service):
    rc_token = req.POST.get('rc_token')

    if rc_token is None:
        return "No RC token."

    rc_user = User.EnsureWithRcToken(req, rc_token)
    rc_uid, rc_authData, rc_extendedAuthData = (rc_token, {}, {
        "token": rc_token
    })
    rc_serviceRecord = Service.EnsureServiceRecordWithAuth(
        RunnersConnectService, rc_uid, rc_authData, rc_extendedAuthData, True)
    User.ConnectService(rc_user, rc_serviceRecord)

    svc = Service.FromID(service)
    from tapiriik.services.api import APIException
    try:
        if svc.RequiresExtendedAuthorizationDetails:
            uid, authData, extendedAuthData = svc.Authorize(
                req.POST["username"], req.POST["password"])
        else:
            uid, authData = svc.Authorize(req.POST["username"],
                                          req.POST["password"])
    except APIException as e:
        if e.UserException is not None:
            return {
                "type": e.UserException.Type,
                "extra": e.UserException.Extra
            }
        return False
    if authData is not None:
        #serviceRecord = Service.EnsureServiceRecordWithAuth(svc, uid, authData, extendedAuthDetails=extendedAuthData if svc.RequiresExtendedAuthorizationDetails else None, persistExtendedAuthDetails=bool(req.POST.get("persist", None)))
        #always persist
        serviceRecord = Service.EnsureServiceRecordWithAuth(
            svc,
            uid,
            authData,
            extendedAuthDetails=extendedAuthData
            if svc.RequiresExtendedAuthorizationDetails else None,
            persistExtendedAuthDetails=bool(True))
        # auth by this service connection
        #existingUser = User.AuthByService(serviceRecord)
        # only log us in as this different user in the case that we don't already have an account
        #if existingUser is not None and req.user is None:
        #    User.Login(existingUser, req)
        #else:
        #    User.Ensure(req)
        # link service to user account, possible merge happens behind the scenes (but doesn't effect active user)
        User.ConnectService(req.user, serviceRecord)
        return True
    return False
Exemple #11
0
def settings(request):
    available_settings = {
        "allow_activity_flow_exception_bypass_via_self": {
            "Title": "Route activities via",
            "Description": "Allows activities to flow through this service to avoid a flow exception that would otherwise prevent them arriving at a destination.",
            "Field": "checkbox"
        },
        "sync_private": {
            "Title": "Sync private activities",
            "Description": "By default, all activities will be synced. Unsetting this will prevent private activities being taken from this service.",
            "Field": "checkbox",
            "Available": ["strava", "runkeeper"]
        }
    }
    conns = User.GetConnectionRecordsByUser(request.user)

    for key, setting in available_settings.items():
        available_settings[key]["Values"] = {}

    for conn in conns:
        config = conn.GetConfiguration()
        for key, setting in available_settings.items():
            if request.method == "POST":
                formkey = key + "_" + conn.Service.ID
                if setting["Field"] == "checkbox":
                    config[key] = formkey in request.POST
            available_settings[key]["Values"][conn.Service.ID] = config[key]

        if request.method == "POST":
            conn.SetConfiguration(config)
    if request.method == "POST":
        return redirect("settings_panel")

    return render(request, "settings.html", {"user": request.user, "settings": available_settings})
Exemple #12
0
 def user_services_sort(service):
     if not request.user:
         return 0
     if User.IsServiceConnected(request.user, service["ID"]):
         return 0
     else:
         return 1
Exemple #13
0
def sync_clear_errorgroup(req, service, group):
    if not req.user:
        return HttpResponse(status=401)

    rec = User.GetConnectionRecord(req.user, service)
    if not rec:
        return HttpResponse(status=404)

    # Prevent this becoming a vehicle for rapid synchronization
    to_clear_count = 0
    for x in rec.SyncErrors:
        if "UserException" in x and "ClearGroup" in x["UserException"] and x[
                "UserException"]["ClearGroup"] == group:
            to_clear_count += 1

    if to_clear_count > 0:
        db.connections.update(
            {"_id": rec._id},
            {"$pull": {
                "SyncErrors": {
                    "UserException.ClearGroup": group
                }
            }})
        db.users.update(
            {"_id": req.user["_id"]},
            {'$inc': {
                "BlockingSyncErrorCount": -to_clear_count
            }}
        )  # In the interests of data integrity, update the summary counts immediately as opposed to waiting for a sync to complete.
        Sync.ScheduleImmediateSync(
            req.user, True
        )  # And schedule them for an immediate full resynchronization, so the now-unblocked services can be brought up to speed.            return HttpResponse()
        return HttpResponse()

    return HttpResponse(status=404)
Exemple #14
0
    def _create(user):
        # Pull all the records that need to be rolled back
        logger.info("Finding activities for %s" % user["_id"])
        conns = User.GetConnectionRecordsByUser(user)
        my_services = [conn.Service.ID for conn in conns]
        my_ext_ids = [conn.ExternalID for conn in conns]
        logger.info("Scanning uploads table for %s accounts with %s extids" %
                    (my_services, my_ext_ids))
        uploads = db.uploaded_activities.find({
            "Service": {
                "$in": my_services
            },
            "UserExternalID": {
                "$in": my_ext_ids
            }
        })
        pending_deletions = {}
        for upload in uploads:
            svc = upload["Service"]
            upload_id = upload["ExternalID"]
            svc_ext_id = upload["UserExternalID"]
            # Filter back down to the pairing we actually need
            if my_services.index(svc) != my_ext_ids.index(svc_ext_id):
                continue
            if svc not in pending_deletions:
                pending_deletions[svc] = []
            pending_deletions[svc].append(upload_id)

        # Another case of "I should have an ORM"
        return RollbackTask({"PendingDeletions": pending_deletions})
    def test_eligibility_flowexception_none(self):
        user = TestTools.create_mock_user()
        svcA, svcB = TestTools.create_mock_services()
        recA = TestTools.create_mock_svc_record(svcA)
        recB = TestTools.create_mock_svc_record(svcB)
        act = TestTools.create_blank_activity(svcA, record=recB)
        act.Origin = recB
        act.UIDs = set([act.UID])
        act.Record = ActivityRecord.FromActivity(act)
        User.SetFlowException(user,
                              recA,
                              recB,
                              flowToSource=False,
                              flowToTarget=False)
        recipientServices = [recA]
        s = SynchronizationTask(None)
        s._excludedServices = {}
        s.user = user
        s._serviceConnections = [recA, recB]
        eligible = s._determineEligibleRecipientServices(
            act, recipientServices)
        self.assertTrue(recA not in eligible)
        self.assertTrue(recB not in eligible)

        recipientServices = [recB]
        act.Origin = recA
        act.ServiceDataCollection = TestTools.create_mock_servicedatacollection(
            svcA, record=recA)
        eligible = s._determineEligibleRecipientServices(
            act, recipientServices)
        self.assertTrue(recA not in eligible)
        self.assertTrue(recB not in eligible)
Exemple #16
0
    def test_eligibility_flowexception_both(self):
        user = TestTools.create_mock_user()
        svcA, svcB = TestTools.create_mock_services()
        recA = TestTools.create_mock_svc_record(svcA)
        recB = TestTools.create_mock_svc_record(svcB)
        act = TestTools.create_blank_activity(svcA, record=recB)
        act.Origin = recB
        User.SetFlowException(user,
                              recA,
                              recB,
                              flowToSource=False,
                              flowToTarget=False)
        recipientServices = [recA, recB]
        excludedServices = []
        eligible = Sync._determineEligibleRecipientServices(
            activity=act,
            connectedServices=recipientServices,
            recipientServices=recipientServices,
            excludedServices=excludedServices,
            user=user)
        self.assertFalse(recA in eligible)
        self.assertTrue(recB in eligible)

        act.Origin = recA
        act.ServiceDataCollection = TestTools.create_mock_servicedatacollection(
            svcA, record=recA)
        eligible = Sync._determineEligibleRecipientServices(
            activity=act,
            connectedServices=recipientServices,
            recipientServices=recipientServices,
            excludedServices=excludedServices,
            user=user)
        self.assertTrue(recA in eligible)
        self.assertFalse(recB in eligible)
Exemple #17
0
def sync_status(req):
    if not req.user:
        return HttpResponse(status=403)

    stats = db.stats.find_one()
    syncHash = 1  # Just used to refresh the dashboard page, until I get on the Angular bandwagon.
    conns = User.GetConnectionRecordsByUser(req.user)
    errorCodes = []
    for conn in conns:
        syncHash = zlib.adler32(bytes(conn.HasExtendedAuthorizationDetails()), syncHash)
        if not hasattr(conn, "SyncErrors"):
            continue
        for err in conn.SyncErrors:
            syncHash = zlib.adler32(bytes(str(err), "UTF-8"), syncHash)
            if "Code" in err and err["Code"] is not None and len(err["Code"]) > 0:
                errorCodes.append(err["Code"])
            else:
                errorCodes.append("SYS-" + err["Step"])
    return HttpResponse(json.dumps({"NextSync": (req.user["NextSynchronization"].ctime() + " UTC") if "NextSynchronization" in req.user and req.user["NextSynchronization"] is not None else None,
                                    "LastSync": (req.user["LastSynchronization"].ctime() + " UTC") if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None else None,
                                    "Synchronizing": "SynchronizationWorker" in req.user,
                                    "SynchronizationProgress": req.user["SynchronizationProgress"] if "SynchronizationProgress" in req.user else None,
                                    "SynchronizationStep": req.user["SynchronizationStep"] if "SynchronizationStep" in req.user else None,
                                    "SynchronizationWaitTime": (stats["QueueHeadTime"] - (datetime.utcnow() - req.user["NextSynchronization"]).total_seconds()) if "NextSynchronization" in req.user and req.user["NextSynchronization"] is not None else None,
                                    "Errors": errorCodes,
                                    "Hash": syncHash}), mimetype="application/json")
Exemple #18
0
def aerobia(req):
    if not req.user:
        return HttpResponse(status=403)
    conn = User.GetConnectionRecord(req.user, "aerobia")

    config = conn.GetConfiguration()
    gearRules = config["gearRules"] if "gearRules" in config else []
    props = {
        'aerobiaId': conn.ExternalID,
        'userToken': conn.Authorization["OAuthToken"],
        'sportTypes': conn.Service.SupportedActivities,
        'config': {
            'gearRules': gearRules
        }
    }

    if req.method == "POST":
        form = AerobiaConfigForm(req.POST)
        if form.is_valid():
            configRaw = req.POST.get('config')
            config = json.loads(configRaw)
            conn.SetConfiguration(config)
            return redirect("dashboard")

    return render(req, "config/aerobia.html", {'props': props})
Exemple #19
0
    def test_eligibility_flowexception_none(self):
        user = TestTools.create_mock_user()
        svcA, svcB = TestTools.create_mock_services()
        recA = TestTools.create_mock_svc_record(svcA)
        recB = TestTools.create_mock_svc_record(svcB)
        act = TestTools.create_blank_activity(svcA, record=recB)
        act.Origin = recB
        User.SetFlowException(user,
                              recA,
                              recB,
                              flowToSource=False,
                              flowToTarget=False)
        recipientServices = [recA]
        excludedServices = []
        eligible = Sync._determineEligibleRecipientServices(
            activity=act,
            recipientServices=recipientServices,
            excludedServices=excludedServices,
            user=user)
        self.assertTrue(recA not in eligible)
        self.assertTrue(recB not in eligible)

        recipientServices = [recB]
        act.Origin = recA
        act.UploadedTo = [
            TestTools.create_mock_upload_record(svcA, record=recA)
        ]
        eligible = Sync._determineEligibleRecipientServices(
            activity=act,
            recipientServices=recipientServices,
            excludedServices=excludedServices,
            user=user)
        self.assertTrue(recA not in eligible)
        self.assertTrue(recB not in eligible)
Exemple #20
0
def auth_do(req, service):
    svc = Service.FromID(service)
    from tapiriik.services.api import APIException
    try:
        if svc.RequiresExtendedAuthorizationDetails:
            uid, authData, extendedAuthData = svc.Authorize(
                req.POST["username"], req.POST["password"])
        else:
            uid, authData = svc.Authorize(req.POST["username"],
                                          req.POST["password"])
    except APIException as e:
        if e.UserException is not None:
            return {
                "type": e.UserException.Type,
                "extra": e.UserException.Extra
            }
        return False
    if authData is not None:
        serviceRecord = Service.EnsureServiceRecordWithAuth(
            svc,
            uid,
            authData,
            extendedAuthDetails=extendedAuthData
            if svc.RequiresExtendedAuthorizationDetails else None,
            persistExtendedAuthDetails=bool(req.POST.get("persist", None)))
        # auth by this service connection
        existingUser = User.AuthByService(serviceRecord)
        # only log us in as this different user in the case that we don't already have an account
        if existingUser is not None and req.user is None:
            User.Login(existingUser, req)
        else:
            User.Ensure(req)
        # link service to user account, possible merge happens behind the scenes (but doesn't effect active user)
        User.ConnectService(req.user, serviceRecord)

        # TODO do other way. May be possible to achieve during LocalService auth?
        # restrict sync to primary server to ensure data is accessible by the web server
        # in case we are connecting local exporter
        if PRIMARY_HOST_NAME:
            db.users.update({"ConnectedServices.Service": service}, {
                "$set": {
                    "SynchronizationHostRestriction": PRIMARY_HOST_NAME
                }
            })

        return True
    return False
Exemple #21
0
def deauth(req, service):  # this is RK-specific
    deauthData = json.loads(req.body.decode("ASCII"))
    token = deauthData["access_token"]
    svc = Service.FromID(service)
    svcRecord = Service.GetServiceRecordWithAuthDetails(svc, {"Token": token})
    Service.DeleteServiceRecord(svcRecord)
    User.DisconnectService(svcRecord)
    return HttpResponse(status=200)
Exemple #22
0
def payments_return(req):
    if req.user is None:
        return redirect("/")

    if User.HasActivePayment(req.user):
        return redirect("payments_confirmed")

    return render(req, "payments/return.html")
Exemple #23
0
 def ApplyPaymentState(self, user, state, externalID, duration=None):
     from tapiriik.payments import Payments
     from tapiriik.auth import User
     if state:
         pmt = Payments.EnsureExternalPayment(self.ID, externalID, duration)
         User.AssociateExternalPayment(user, pmt)
     else:
         Payments.ExpireExternalPayment(self.ID, externalID)
Exemple #24
0
 def _applyPaymentState(self, serviceRecord):
     from tapiriik.auth import User
     state = self._getPaymentState(serviceRecord)
     ExternalPaymentProvider.FromID("motivato").ApplyPaymentState(
         User.GetByConnection(serviceRecord),
         state,
         serviceRecord.ExternalID,
         duration=None)
Exemple #25
0
def sync_status(req):
    if not req.user:
        return HttpResponse(status=403)

    stats = db.stats.find_one()
    syncHash = 1  # Just used to refresh the dashboard page, until I get on the Angular bandwagon.
    conns = User.GetConnectionRecordsByUser(req.user)

    def svc_id(svc):
        return svc.Service.ID

    def err_msg(err):
        return err["Message"]

    for conn in sorted(conns, key=svc_id):
        syncHash = zlib.adler32(bytes(conn.HasExtendedAuthorizationDetails()),
                                syncHash)
        if not hasattr(conn, "SyncErrors"):
            continue
        for err in sorted(conn.SyncErrors, key=err_msg):
            syncHash = zlib.adler32(bytes(err_msg(err), "UTF-8"), syncHash)

    # Flatten NextSynchronization with QueuedAt
    pendingSyncTime = req.user[
        "NextSynchronization"] if "NextSynchronization" in req.user else None
    if "QueuedAt" in req.user and req.user["QueuedAt"]:
        pendingSyncTime = req.user["QueuedAt"]

    sync_status_dict = {
        "NextSync":
        (pendingSyncTime.ctime() + " UTC") if pendingSyncTime else None,
        "LastSync": (req.user["LastSynchronization"].ctime() +
                     " UTC") if "LastSynchronization" in req.user
        and req.user["LastSynchronization"] is not None else None,
        "Synchronizing":
        "SynchronizationWorker" in req.user,
        "SynchronizationProgress":
        req.user["SynchronizationProgress"]
        if "SynchronizationProgress" in req.user else None,
        "SynchronizationStep":
        req.user["SynchronizationStep"]
        if "SynchronizationStep" in req.user else None,
        "SynchronizationWaitTime":
        None,  # I wish.
        "Hash":
        syncHash
    }

    if stats and "QueueHeadTime" in stats:
        sync_status_dict["SynchronizationWaitTime"] = (
            stats["QueueHeadTime"] -
            (datetime.utcnow() -
             req.user["NextSynchronization"]).total_seconds()
        ) if "NextSynchronization" in req.user and req.user[
            "NextSynchronization"] is not None else None

    return HttpResponse(json.dumps(sync_status_dict),
                        content_type="application/json")
Exemple #26
0
    def _determineEligibleRecipientServices(activity, recipientServices,
                                            excludedServices, user):
        from tapiriik.auth import User
        eligibleServices = []
        for destinationSvcRecord in recipientServices:
            if destinationSvcRecord in excludedServices:
                logger.info("\t\tExcluded " + destinationSvcRecord.Service.ID)
                continue  # we don't know for sure if it needs to be uploaded, hold off for now
            flowException = False

            sources = [x["Connection"] for x in activity.UploadedTo]
            if hasattr(activity, "Origin"):
                sources = [activity.Origin]
            for src in sources:
                if User.CheckFlowException(user, src, destinationSvcRecord):
                    flowException = True
                    break
            # This isn't an absolute failure - it's possible we could still take an indirect route around this exception
            # But only if they've allowed it
            if flowException:
                # Eventual destinations, since it'd eventually be synced from these anyways
                secondLevelSources = [
                    x for x in recipientServices if x != destinationSvcRecord
                ]
                # Other places this activity exists - the alternate routes
                secondLevelSources += [
                    x["Connection"] for x in activity.UploadedTo
                ]
                for secondLevelSrc in secondLevelSources:
                    if secondLevelSrc.GetConfiguration(
                    )["allow_activity_flow_exception_bypass_via_self"] and not User.CheckFlowException(
                            user, secondLevelSrc, destinationSvcRecord):
                        flowException = False
                        break

            if flowException:
                logger.info("\t\tFlow exception for " +
                            destinationSvcRecord.Service.ID)
                continue
            destSvc = destinationSvcRecord.Service
            if destSvc.RequiresConfiguration(destinationSvcRecord):
                logger.info("\t\t" + destSvc.ID + " not configured")
                continue  # not configured, so we won't even try
            eligibleServices.append(destinationSvcRecord)
        return eligibleServices
Exemple #27
0
def authreturn(req, service, level=None):
    rc_token = req.GET.get('rc_token')

    if rc_token is None:
        return redirect("https://app.runnersconnect.net")

    rc_user = User.EnsureWithRcToken(req, rc_token)
    rc_uid, rc_authData, rc_extendedAuthData = (rc_token, {}, {"token": rc_token})
    rc_serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, rc_uid, rc_authData, rc_extendedAuthData, True)
    User.ConnectService(rc_user, rc_serviceRecord)

    logger.info("Auto logged user %s " % (req.user['rc_token']))

    if ("error" in req.GET or "not_approved" in req.GET):
        success = False
    else:
        svc = Service.FromID(service)
        try:
            uid, authData = svc.RetrieveAuthorizationToken(req, level)
        except Exception as e:
            logger.info("Errrrr %s " % (str(e)))
            return render(req, "oauth-failure.html", {
                "service": svc,
                "error": str(e)
            })
        serviceRecord = Service.EnsureServiceRecordWithAuth(svc, uid, authData)

        # auth by this service connection
        # we've already created and logged in user with rc token
        #existingUser = User.AuthByService(serviceRecord)

        # only log us in as this different user in the case that we don't already have an account
        #if req.user is None and existingUser is not None:
        #    User.Login(existingUser, req)
        #else:
        #    User.Ensure(req)
        # link service to user account, possible merge happens behind the scenes (but doesn't effect active user)
        User.ConnectService(req.user, serviceRecord)
        success = True

    #return render(req, "oauth-return.html", {"success": 1 if success else 0})
    connectedServices = [s["Service"] for s in req.user['ConnectedServices']]
    logger.info("connected services  %s " % (connectedServices))

    return HttpResponse(json.dumps({"success": success == True, "user": req.user["rc_token"], "connectedServices": connectedServices}), content_type='application/json')
Exemple #28
0
def config_save(req, service):
    if not req.user:
        return HttpResponse(status=403)

    conn = User.GetConnectionRecord(req.user, service)
    if not conn:
        return HttpResponse(status=404)
    conn.SetConfiguration(json.loads(req.POST["config"]))
    return HttpResponse()
Exemple #29
0
def schedule_immediate_rc_sync(req):
    token = req.POST.get('token')

    if token is None:
        return HttpResponse(status=403)

    user = User.EnsureWithRcToken(req, token)
    uid, authData, extendedAuthData = (token, {}, {"token": token})
    serviceRecord = Service.EnsureServiceRecordWithAuth(RunnersConnectService, uid, authData, extendedAuthData, True)
    User.ConnectService(user, serviceRecord)

    #if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None and datetime.utcnow() - req.user["LastSynchronization"] < Sync.MinimumSyncInterval:
    #    return HttpResponse(status=429)
    exhaustive = None
    #if "LastSynchronization" in req.user and req.user["LastSynchronization"] is not None and datetime.utcnow() - req.user["LastSynchronization"] > Sync.MaximumIntervalBeforeExhaustiveSync:
    #    exhaustive = True
    Sync.ScheduleImmediateSync(req.user, exhaustive)
    return HttpResponse()
Exemple #30
0
 def ConfigurationUpdating(self, svcRec, newConfig, oldConfig):
     from tapiriik.sync import Sync
     from tapiriik.auth import User
     if newConfig["SyncRoot"] != oldConfig["SyncRoot"]:
         Sync.ScheduleImmediateSync(User.AuthByService(svcRec), True)
         cachedb.dropbox_cache.update({"ExternalID": svcRec.ExternalID},
                                      {"$unset": {
                                          "Structure": None
                                      }})