mirror of
https://github.com/mozilla/fxa.git
synced 2025-12-13 20:36:41 +01:00
chore(): delete old AppError/OauthError code
This commit is contained in:
@@ -8,10 +8,6 @@ import { execSync } from 'child_process';
|
||||
|
||||
// Maintain List of frozen files here!
|
||||
const frozen: Array<{ pattern: string; reason: string }> = [
|
||||
{
|
||||
pattern: 'packages/fxa-auth-server/(lib|lib/oauth)/error.js',
|
||||
reason: 'Files moved to libs/accounts/errors',
|
||||
},
|
||||
{
|
||||
pattern: 'packages/fxa-auth-server/lib/senders/email.js',
|
||||
reason: 'Files moved to libs/accounts/email-sender',
|
||||
|
||||
@@ -10,9 +10,10 @@ import {
|
||||
DEFAULT_ERRROR,
|
||||
IGNORED_ERROR_NUMBERS,
|
||||
DEBUGGABLE_PAYLOAD_KEYS,
|
||||
OAUTH_ERRNO,
|
||||
} from './constants';
|
||||
import { OauthError } from './oauth-error';
|
||||
import { Request as HapiRequest } from 'hapi';
|
||||
import type { Request as HapiRequest } from 'hapi';
|
||||
|
||||
/**
|
||||
* Augmented Hapi request. Extends request.app interface auth-server specific feilds that this lib uses.
|
||||
@@ -296,7 +297,7 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static accountExists(email: string) {
|
||||
static accountExists(email?: string) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -310,7 +311,7 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static unknownAccount(email: string) {
|
||||
static unknownAccount(email?: string) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -387,7 +388,7 @@ export class AppError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
static invalidVerificationCode(details: Record<string, any>) {
|
||||
static invalidVerificationCode(details?: Record<string, any>) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -408,7 +409,7 @@ export class AppError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
static invalidRequestParameter(validation: string) {
|
||||
static invalidRequestParameter(validation?: unknown) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -422,7 +423,7 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static missingRequestParameter(param: string) {
|
||||
static missingRequestParameter(param?: string) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -486,7 +487,7 @@ export class AppError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
static unauthorized(reason: string) {
|
||||
static unauthorized(reason?: string) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 401,
|
||||
@@ -575,7 +576,7 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static serviceUnavailable(retryAfter: number) {
|
||||
static serviceUnavailable(retryAfter?: number) {
|
||||
if (!retryAfter) {
|
||||
retryAfter = 30;
|
||||
}
|
||||
@@ -595,7 +596,7 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static featureNotEnabled(retryAfter: number) {
|
||||
static featureNotEnabled(retryAfter?: number) {
|
||||
if (!retryAfter) {
|
||||
retryAfter = 30;
|
||||
}
|
||||
@@ -656,7 +657,7 @@ export class AppError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
static deviceSessionConflict(deviceId: string) {
|
||||
static deviceSessionConflict(deviceId?: string) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -770,7 +771,10 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static currencyCountryMismatch(currency: string, country: string) {
|
||||
static currencyCountryMismatch(
|
||||
currency?: string | null,
|
||||
country?: string | null
|
||||
) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -785,7 +789,10 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static currencyCurrencyMismatch(currencyA: string, currencyB: string) {
|
||||
static currencyCurrencyMismatch(
|
||||
currencyA?: string | null,
|
||||
currencyB?: string | null
|
||||
) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -1249,6 +1256,15 @@ export class AppError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
static oauthNotPublicClient() {
|
||||
return new AppError({
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: OAUTH_ERRNO.NOT_PUBLIC_CLIENT,
|
||||
message: 'Not a public client',
|
||||
});
|
||||
}
|
||||
|
||||
static redisConflict() {
|
||||
return new AppError({
|
||||
code: 409,
|
||||
@@ -1376,7 +1392,8 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static unknownCustomer(uid?: string) {
|
||||
static unknownCustomer(uid?: string | { id?: string | null } | null) {
|
||||
const resolvedUid = typeof uid === 'string' ? uid : (uid?.id ?? undefined);
|
||||
return new AppError(
|
||||
{
|
||||
code: 404,
|
||||
@@ -1385,7 +1402,7 @@ export class AppError extends Error {
|
||||
message: 'Unknown customer',
|
||||
},
|
||||
{
|
||||
uid,
|
||||
uid: resolvedUid,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1433,8 +1450,8 @@ export class AppError extends Error {
|
||||
}
|
||||
|
||||
static rejectedSubscriptionPaymentToken(
|
||||
message: string,
|
||||
paymentError: Error
|
||||
message?: string,
|
||||
paymentError?: Error
|
||||
) {
|
||||
return new AppError(
|
||||
{
|
||||
@@ -1443,11 +1460,13 @@ export class AppError extends Error {
|
||||
errno: ERRNO.REJECTED_SUBSCRIPTION_PAYMENT_TOKEN,
|
||||
message,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
paymentError
|
||||
);
|
||||
}
|
||||
|
||||
static rejectedCustomerUpdate(message: string, paymentError: Error) {
|
||||
static rejectedCustomerUpdate(message?: string, paymentError?: Error) {
|
||||
return new AppError(
|
||||
{
|
||||
code: 400,
|
||||
@@ -1455,6 +1474,8 @@ export class AppError extends Error {
|
||||
errno: ERRNO.REJECTED_CUSTOMER_UPDATE,
|
||||
message,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
paymentError
|
||||
);
|
||||
}
|
||||
@@ -1541,9 +1562,9 @@ export class AppError extends Error {
|
||||
|
||||
static invalidInvoicePreviewRequest(
|
||||
error: Error,
|
||||
message: string,
|
||||
priceId: string,
|
||||
customer: string
|
||||
message?: string,
|
||||
priceId?: string,
|
||||
customer?: string
|
||||
) {
|
||||
const extra = error ? [{}, undefined, error] : [];
|
||||
return new AppError(
|
||||
@@ -1638,7 +1659,12 @@ export class AppError extends Error {
|
||||
);
|
||||
}
|
||||
|
||||
static internalValidationError(op: string, data: unknown, error: Error) {
|
||||
static internalValidationError(
|
||||
op: string,
|
||||
data?: unknown,
|
||||
error?: Error | string
|
||||
) {
|
||||
const errInstance = typeof error === 'string' ? new Error(error) : error;
|
||||
return new AppError(
|
||||
{
|
||||
code: 500,
|
||||
@@ -1651,7 +1677,7 @@ export class AppError extends Error {
|
||||
data,
|
||||
},
|
||||
{},
|
||||
error
|
||||
errInstance
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,33 @@ export const ERRNO = {
|
||||
UNEXPECTED_ERROR: 999,
|
||||
};
|
||||
|
||||
export const OAUTH_ERRNO = {
|
||||
UNKNOWN_CLIENT: 101,
|
||||
INCORRECT_SECRET: 102,
|
||||
INCORRECT_REDIRECT: 103,
|
||||
INVALID_ASSERTION: 104,
|
||||
UNKNOWN_CODE: 105,
|
||||
INCORRECT_CODE: 106,
|
||||
EXPIRED_CODE: 107,
|
||||
INVALID_TOKEN: 108,
|
||||
INVALID_PARAMETER: 109,
|
||||
INVALID_RESPONSE_TYPE: 110,
|
||||
UNAUTHORIZED: 111,
|
||||
FORBIDDEN: 112,
|
||||
INVALID_CONTENT_TYPE: 113,
|
||||
INVALID_SCOPES: 114,
|
||||
EXPIRED_TOKEN: 115,
|
||||
NOT_PUBLIC_CLIENT: 116,
|
||||
INCORRECT_CODE_CHALLENGE: 117,
|
||||
MISSING_PKCE_PARAMETERS: 118,
|
||||
STALE_AUTH_AT: 119,
|
||||
MISMATCH_ACR_VALUES: 120,
|
||||
INVALID_GRANT_TYPE: 121,
|
||||
UNKNOWN_TOKEN: 122,
|
||||
SERVER_UNAVAILABLE: 201,
|
||||
DISABLED_CLIENT_ID: 202,
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes an object and swaps keys with values. Useful when a value -> key look up is needed.
|
||||
* @param obj - Object to swap keys and values on
|
||||
@@ -149,6 +176,7 @@ function swapObjectKeysAndValues(obj: { [key: string]: string | number }) {
|
||||
* A reversed map of errnos.
|
||||
*/
|
||||
export const ERRNO_REVERSE_MAP = swapObjectKeysAndValues(ERRNO);
|
||||
export const OAUTH_ERRNO_REVERSE_MAP = swapObjectKeysAndValues(OAUTH_ERRNO);
|
||||
|
||||
/**
|
||||
* The Default Unexpected Error State
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
export * from './constants';
|
||||
export * from './app-error';
|
||||
export * from './oauth-error';
|
||||
export * from './util';
|
||||
|
||||
@@ -59,7 +59,7 @@ if (config.subscriptions && config.subscriptions.stripeApiKey) {
|
||||
}
|
||||
}
|
||||
|
||||
const error = require('../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const Token = require('../lib/tokens')(log, config);
|
||||
const SQSReceiver = require('../lib/sqs')(log, statsd);
|
||||
const bounces = require('../lib/email/bounces')(log, error, config);
|
||||
|
||||
@@ -24,7 +24,7 @@ const {
|
||||
} = require('@fxa/shared/cms');
|
||||
const TracingProvider = require('fxa-shared/tracing/node-tracing');
|
||||
|
||||
const error = require('../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const { JWTool } = require('@fxa/vendored/jwtool');
|
||||
const { StatsD } = require('hot-shots');
|
||||
const { Container } = require('typedi');
|
||||
|
||||
@@ -13,7 +13,7 @@ import { StatsD } from 'hot-shots';
|
||||
import * as Sentry from '@sentry/node';
|
||||
|
||||
import { ConfigType } from '../config';
|
||||
import { ERRNO } from './error';
|
||||
import { ERRNO } from '@fxa/accounts/errors';
|
||||
import OAuthDb from './oauth/db';
|
||||
import { AppleIAP } from './payments/iap/apple-app-store/apple-iap';
|
||||
import { PlayBilling } from './payments/iap/google-play/play-billing';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('./error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
// Maps our variety of verification methods down to a few short standard
|
||||
// "authentication method reference" strings that we're happy to expose to
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('./error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
module.exports = (config, db) => {
|
||||
const configBounces = (config.smtp && config.smtp.bounces) || {};
|
||||
|
||||
@@ -30,7 +30,7 @@ import { normalizeEmail } from 'fxa-shared/email/helpers';
|
||||
import { StatsD } from 'hot-shots';
|
||||
import { Container } from 'typedi';
|
||||
import random, { base32 } from './crypto/random';
|
||||
import error from './error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import {
|
||||
verificationMethodToString,
|
||||
VerificationMethod,
|
||||
@@ -1064,15 +1064,15 @@ export const createDB = (
|
||||
);
|
||||
}
|
||||
|
||||
async verifiedLoginSecurityEventsByUid(params: { uid: string; skipTimeframeMs: number}) {
|
||||
async verifiedLoginSecurityEventsByUid(params: {
|
||||
uid: string;
|
||||
skipTimeframeMs: number;
|
||||
}) {
|
||||
log.trace('DB.verifiedLoginSecurityEventsByUid', {
|
||||
params: params,
|
||||
});
|
||||
const { uid, skipTimeframeMs } = params;
|
||||
return SecurityEvent.findByUidAndVerifiedLogin(
|
||||
uid,
|
||||
skipTimeframeMs
|
||||
);
|
||||
return SecurityEvent.findByUidAndVerifiedLogin(uid, skipTimeframeMs);
|
||||
}
|
||||
|
||||
async securityEventsByUid(params: { uid: string }) {
|
||||
|
||||
@@ -8,7 +8,7 @@ const isA = require('joi');
|
||||
const Sentry = require('@sentry/node');
|
||||
const DESCRIPTION = require('../docs/swagger/shared/descriptions').default;
|
||||
const validators = require('./routes/validators');
|
||||
const error = require('./error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const oauthDB = require('./oauth/db');
|
||||
const { DISPLAY_SAFE_UNICODE_WITH_NON_BMP, HEX_STRING, URL_SAFE_BASE_64 } =
|
||||
validators;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import { ConfigType } from '../config';
|
||||
import { AuthRequest } from './types';
|
||||
import { IncomingHttpHeaders } from 'http';
|
||||
import AppError from './error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import {
|
||||
InactiveAccountsManager,
|
||||
emailTypeToHandlerVals,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
const ACTIVITY_EVENTS = new Set([
|
||||
'account.changedPassword',
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { version } from '../../../package.json';
|
||||
import { createHash } from 'crypto';
|
||||
import { AuthRequest } from '../../types';
|
||||
import * as AppError from '../../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import { clientId as clientIdValidator } from '../../oauth/validators';
|
||||
import { MetricsContext } from '@fxa/shared/metrics/glean';
|
||||
|
||||
@@ -423,7 +423,7 @@ export function gleanMetrics(config: ConfigType) {
|
||||
knownIp: createEventFn('login_confirm_skip_for_known_ip'),
|
||||
newAccount: createEventFn('login_confirm_skip_for_new_account'),
|
||||
knownDevice: createEventFn('login_confirm_skip_for_known_device'),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const logger = require('./log')(
|
||||
'configure-sentry'
|
||||
);
|
||||
const { version } = require('../package.json');
|
||||
const { ignoreErrors } = require('./error');
|
||||
const { ignoreErrors } = require('@fxa/accounts/errors');
|
||||
|
||||
/**
|
||||
* Initialize sentry & otel
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
const Joi = require('joi');
|
||||
const validators = require('./validators');
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const { config } = require('../../config');
|
||||
const { verifyJWT } = require('../../lib/serverJWT');
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
const ScopeSet = require('fxa-shared').oauth.scopes;
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const token = require('./token');
|
||||
const validators = require('./validators');
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const oauthDB = require('./db');
|
||||
const ScopeSet = require('fxa-shared').oauth.scopes;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ const crypto = require('crypto');
|
||||
const buf = (v) => (Buffer.isBuffer(v) ? v : Buffer.from(v, 'hex'));
|
||||
const Joi = require('joi');
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const validators = require('./validators');
|
||||
const db = require('./db');
|
||||
const encrypt = require('fxa-shared/auth/encrypt');
|
||||
@@ -59,7 +59,7 @@ module.exports.getClientCredentials = function getClientCredentials(
|
||||
// the Authorization header or request body, but not both.
|
||||
if (headers.authorization) {
|
||||
const authzMatch = validators.BASIC_AUTH_HEADER.exec(headers.authorization);
|
||||
const err = new OauthError.invalidRequestParameter({
|
||||
const err = OauthError.invalidRequestParameter({
|
||||
keys: ['authorization'],
|
||||
});
|
||||
if (!authzMatch || creds.client_id || creds.client_secret) {
|
||||
@@ -106,7 +106,7 @@ module.exports.authenticateClient = async function authenticateClient(
|
||||
// and should never submit a client_secret.
|
||||
if (client.publicClient) {
|
||||
if (creds.client_secret) {
|
||||
throw new OauthError.invalidRequestParameter({ keys: ['client_secret'] });
|
||||
throw OauthError.invalidRequestParameter({ keys: ['client_secret'] });
|
||||
}
|
||||
return client;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ module.exports.authenticateClient = async function authenticateClient(
|
||||
// Check client_secret against both current and previous stored secrets,
|
||||
// to allow for seamless rotation of the secret.
|
||||
if (!creds.client_secret) {
|
||||
throw new OauthError.invalidRequestParameter({ keys: ['client_secret'] });
|
||||
throw OauthError.invalidRequestParameter({ keys: ['client_secret'] });
|
||||
}
|
||||
const submitted = encrypt.hash(buf(creds.client_secret));
|
||||
const stored = client.hashedSecret;
|
||||
|
||||
@@ -1,387 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const util = require('util');
|
||||
const hex = (v) => (Buffer.isBuffer(v) ? v.toString('hex') : v);
|
||||
|
||||
const DEFAULTS = {
|
||||
code: 500,
|
||||
error: 'Internal Server Error',
|
||||
errno: 999,
|
||||
info: 'https://mozilla.github.io/ecosystem-platform/api#section/Errors',
|
||||
message: 'Unspecified error',
|
||||
};
|
||||
|
||||
function merge(target, other) {
|
||||
var keys = Object.keys(other || {});
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
target[keys[i]] = other[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated. New error types should be defined in lib/error.js
|
||||
function OauthError(options, extra, headers) {
|
||||
this.message = options.message || DEFAULTS.message;
|
||||
this.isBoom = true;
|
||||
if (options.stack) {
|
||||
this.stack = options.stack;
|
||||
} else {
|
||||
Error.captureStackTrace(this, OauthError);
|
||||
}
|
||||
this.errno = options.errno || DEFAULTS.errno;
|
||||
this.output = {
|
||||
statusCode: options.code || DEFAULTS.code,
|
||||
payload: {
|
||||
code: options.code || DEFAULTS.code,
|
||||
errno: this.errno,
|
||||
error: options.error || DEFAULTS.error,
|
||||
message: this.message,
|
||||
info: options.info || DEFAULTS.info,
|
||||
},
|
||||
headers: headers || {},
|
||||
};
|
||||
merge(this.output.payload, extra);
|
||||
}
|
||||
util.inherits(OauthError, Error);
|
||||
|
||||
OauthError.prototype.toString = function () {
|
||||
return 'Error: ' + this.message;
|
||||
};
|
||||
|
||||
OauthError.prototype.header = function (name, value) {
|
||||
this.output.headers[name] = value;
|
||||
};
|
||||
|
||||
OauthError.isOauthRoute = function isOauthRoute(path) {
|
||||
const routes = require('../routes/oauth')();
|
||||
// ironically, routes that include "oauth" are considered auth-server routes
|
||||
return (
|
||||
// For now we use a fragile heuristic that all oauth routes set cors config
|
||||
// TODO: when we merge oauth errors into auth, rethink this.
|
||||
routes.findIndex((r) => `/v1${r.path}` === path && r.config.cors) > -1
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.translate = function translate(response) {
|
||||
if (response instanceof OauthError) {
|
||||
return response;
|
||||
}
|
||||
|
||||
var error;
|
||||
var payload = response.output.payload;
|
||||
if (payload.validation) {
|
||||
error = OauthError.invalidRequestParameter(payload.validation);
|
||||
} else if (payload.statusCode === 415) {
|
||||
error = OauthError.invalidContentType();
|
||||
} else {
|
||||
error = new OauthError({
|
||||
message: payload.message,
|
||||
code: payload.statusCode,
|
||||
error: payload.error,
|
||||
errno: payload.errno,
|
||||
stack: response.stack,
|
||||
});
|
||||
}
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
OauthError.prototype.backtrace = function (traced) {
|
||||
this.output.payload.log = traced;
|
||||
};
|
||||
|
||||
OauthError.unexpectedError = function unexpectedError() {
|
||||
return new OauthError({});
|
||||
};
|
||||
|
||||
OauthError.unknownClient = function unknownClient(clientId) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 101,
|
||||
message: 'Unknown client',
|
||||
},
|
||||
{
|
||||
clientId: hex(clientId),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.incorrectSecret = function incorrectSecret(clientId) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 102,
|
||||
message: 'Incorrect secret',
|
||||
},
|
||||
{
|
||||
clientId: hex(clientId),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.incorrectRedirect = function incorrectRedirect(uri) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 103,
|
||||
message: 'Incorrect redirect_uri',
|
||||
},
|
||||
{
|
||||
redirectUri: uri,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.invalidAssertion = function invalidAssertion() {
|
||||
return new OauthError({
|
||||
code: 401,
|
||||
error: 'Bad Request',
|
||||
errno: 104,
|
||||
message: 'Invalid assertion',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.unknownCode = function unknownCode(code) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 105,
|
||||
message: 'Unknown code',
|
||||
},
|
||||
{
|
||||
requestCode: code,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.mismatchCode = function mismatchCode(code, clientId) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 106,
|
||||
message: 'Incorrect code',
|
||||
},
|
||||
{
|
||||
requestCode: hex(code),
|
||||
client: hex(clientId),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.expiredCode = function expiredCode(code, expiredAt) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 107,
|
||||
message: 'Expired code',
|
||||
},
|
||||
{
|
||||
requestCode: hex(code),
|
||||
expiredAt: expiredAt,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.invalidToken = function invalidToken() {
|
||||
return new OauthError({
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 108,
|
||||
message: 'Invalid token',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.invalidRequestParameter = function invalidRequestParameter(val) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 109,
|
||||
message: 'Invalid request parameter',
|
||||
},
|
||||
{
|
||||
validation: val,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.invalidResponseType = function invalidResponseType() {
|
||||
return new OauthError({
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 110,
|
||||
message: 'Invalid response_type',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.unauthorized = function unauthorized(reason) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 401,
|
||||
error: 'Unauthorized',
|
||||
errno: 111,
|
||||
message: 'Unauthorized for route',
|
||||
},
|
||||
{
|
||||
detail: reason,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.forbidden = function forbidden() {
|
||||
return new OauthError({
|
||||
code: 403,
|
||||
error: 'Forbidden',
|
||||
errno: 112,
|
||||
message: 'Forbidden',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.invalidContentType = function invalidContentType() {
|
||||
return new OauthError({
|
||||
code: 415,
|
||||
error: 'Unsupported Media Type',
|
||||
errno: 113,
|
||||
message:
|
||||
'Content-Type must be either application/json or ' +
|
||||
'application/x-www-form-urlencoded',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.invalidScopes = function invalidScopes(scopes) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Invalid scopes',
|
||||
errno: 114,
|
||||
message: 'Requested scopes are not allowed',
|
||||
},
|
||||
{
|
||||
invalidScopes: scopes,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.expiredToken = function expiredToken(expiredAt) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 115,
|
||||
message: 'Expired token',
|
||||
},
|
||||
{
|
||||
expiredAt: expiredAt,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.notPublicClient = function notPublicClient(clientId) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 116,
|
||||
message: 'Not a public client',
|
||||
},
|
||||
{
|
||||
clientId: hex(clientId),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.mismatchCodeChallenge = function mismatchCodeChallenge(
|
||||
pkceHashValue
|
||||
) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 117,
|
||||
message: 'Incorrect code_challenge',
|
||||
},
|
||||
{
|
||||
requestCodeChallenge: pkceHashValue,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.missingPkceParameters = function missingPkceParameters() {
|
||||
return new OauthError({
|
||||
code: 400,
|
||||
error: 'PKCE parameters missing',
|
||||
errno: 118,
|
||||
message: 'Public clients require PKCE OAuth parameters',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.staleAuthAt = function staleAuthAt(authAt) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 401,
|
||||
error: 'Bad Request',
|
||||
errno: 119,
|
||||
message: 'Stale authentication timestamp',
|
||||
},
|
||||
{
|
||||
authAt: authAt,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.mismatchAcr = function mismatchAcr(foundValue) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 120,
|
||||
message: 'Mismatch acr value',
|
||||
},
|
||||
{ foundValue }
|
||||
);
|
||||
};
|
||||
|
||||
OauthError.invalidGrantType = function invalidGrantType() {
|
||||
return new OauthError({
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 121,
|
||||
message: 'Invalid grant_type',
|
||||
});
|
||||
};
|
||||
|
||||
OauthError.unknownToken = function unknownToken() {
|
||||
return new OauthError({
|
||||
code: 400,
|
||||
error: 'Bad Request',
|
||||
errno: 122,
|
||||
message: 'Unknown token',
|
||||
});
|
||||
};
|
||||
|
||||
// N.B. `errno: 201` is traditionally our generic "service unavailable" error,
|
||||
// so let's reserve it for that purpose here as well.
|
||||
|
||||
OauthError.disabledClient = function disabledClient(clientId) {
|
||||
return new OauthError(
|
||||
{
|
||||
code: 503,
|
||||
error: 'Client Disabled',
|
||||
errno: 202, // TODO reconcile this with the auth-server version
|
||||
message: 'This client has been temporarily disabled',
|
||||
},
|
||||
{ clientId }
|
||||
);
|
||||
};
|
||||
|
||||
// Deprecated. New error types should be defined in lib/error.js
|
||||
|
||||
module.exports = OauthError;
|
||||
@@ -6,7 +6,7 @@ const { Container } = require('typedi');
|
||||
|
||||
const { CapabilityService } = require('../payments/capability');
|
||||
const { config } = require('../../config');
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const db = require('./db');
|
||||
const util = require('./util');
|
||||
const ScopeSet = require('fxa-shared').oauth.scopes;
|
||||
@@ -46,7 +46,6 @@ const TRUSTED_CLIENT_ALLOWED_SCOPES = ScopeSet.fromArray([
|
||||
'profile:subscriptions',
|
||||
]);
|
||||
|
||||
|
||||
/** @type {CapabilityService} */
|
||||
let capabilityService = undefined;
|
||||
|
||||
@@ -116,9 +115,13 @@ module.exports.validateRequestedGrant = async function validateRequestedGrant(
|
||||
// For trusted clients, validate scopes against clients trusted scopes
|
||||
if (client.trusted) {
|
||||
const clientScopeSet = ScopeSet.fromString(client.allowedScopes || '');
|
||||
const trustedClientAllowedScopes = clientScopeSet.union(TRUSTED_CLIENT_ALLOWED_SCOPES);
|
||||
const trustedClientAllowedScopes = clientScopeSet.union(
|
||||
TRUSTED_CLIENT_ALLOWED_SCOPES
|
||||
);
|
||||
|
||||
const invalidScopes = requestedGrant.scope.difference(trustedClientAllowedScopes);
|
||||
const invalidScopes = requestedGrant.scope.difference(
|
||||
trustedClientAllowedScopes
|
||||
);
|
||||
if (!invalidScopes.isEmpty()) {
|
||||
if (config.get('oauthServer.strictScopeValidation')) {
|
||||
// Strict mode: remove invalid scopes
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const jwt = require('./jwt');
|
||||
const sub = require('./jwt_sub');
|
||||
const { OAUTH_SCOPE_OLD_SYNC } = require('fxa-shared/oauth/constants');
|
||||
@@ -23,8 +23,8 @@ exports.create = async function generateJWTAccessToken(accessToken, grant) {
|
||||
const audience = grant.resource
|
||||
? [clientId, grant.resource]
|
||||
: grant.scope.contains(OAUTH_SCOPE_OLD_SYNC)
|
||||
? TOKEN_SERVER_URL
|
||||
: clientId;
|
||||
? TOKEN_SERVER_URL
|
||||
: clientId;
|
||||
|
||||
// Claims list from:
|
||||
// https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt#section-2.2
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const jwt = require('./jwt');
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
const ScopeSet = require('fxa-shared').oauth.scopes;
|
||||
|
||||
const OauthError = require('./error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const { config } = require('../../config');
|
||||
const db = require('./db');
|
||||
const encrypt = require('fxa-shared/auth/encrypt');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const AuthError = require('../error');
|
||||
const { AppError: AuthError } = require('@fxa/accounts/errors');
|
||||
const { signJWT } = require('../serverJWT');
|
||||
const crypto = require('crypto');
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { SeverityLevel } from '@sentry/core';
|
||||
|
||||
import error from '../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { authEvents } from '../events';
|
||||
import { AppConfig, AuthLogger, AuthRequest } from '../types';
|
||||
import { ConfigType } from '../../config';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { randomUUID } from 'crypto';
|
||||
import { Logger } from 'mozlog';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import errors from '../../error';
|
||||
import { AppError as errors } from '@fxa/accounts/errors';
|
||||
import { AppConfig, AuthFirestore, AuthLogger } from '../../types';
|
||||
|
||||
import {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { AppendedAppStoreSubscriptionPurchase } from 'fxa-shared/payments/iap/ap
|
||||
import { MozillaSubscriptionTypes } from 'fxa-shared/subscriptions/types';
|
||||
import Container from 'typedi';
|
||||
|
||||
import { internalValidationError } from '../../../../lib/error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import { AppConfig } from '../../../types';
|
||||
import { StripeHelper } from '../../stripe';
|
||||
import { SubscriptionsService } from '../types';
|
||||
@@ -20,7 +20,7 @@ export class AppStoreSubscriptions
|
||||
constructor() {
|
||||
const config = Container.get(AppConfig);
|
||||
if (!config.subscriptions.enabled) {
|
||||
throw internalValidationError(
|
||||
throw AppError.internalValidationError(
|
||||
'AppStoreSubscriptions',
|
||||
{},
|
||||
new Error(
|
||||
@@ -30,7 +30,7 @@ export class AppStoreSubscriptions
|
||||
}
|
||||
|
||||
if (!Container.has(StripeHelper)) {
|
||||
throw internalValidationError(
|
||||
throw AppError.internalValidationError(
|
||||
'AppStoreSubscriptions',
|
||||
{},
|
||||
new Error(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { MozillaSubscriptionTypes } from 'fxa-shared/subscriptions/types';
|
||||
import Container from 'typedi';
|
||||
|
||||
import { internalValidationError } from '../../../../lib/error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import { AppConfig } from '../../../types';
|
||||
import { StripeHelper } from '../../stripe';
|
||||
import { SubscriptionsService } from '../types';
|
||||
@@ -20,7 +20,7 @@ export class PlaySubscriptions
|
||||
constructor() {
|
||||
const config = Container.get(AppConfig);
|
||||
if (!config.subscriptions.enabled) {
|
||||
throw internalValidationError(
|
||||
throw AppError.internalValidationError(
|
||||
'PlaySubscriptions',
|
||||
{},
|
||||
new Error(
|
||||
@@ -30,7 +30,7 @@ export class PlaySubscriptions
|
||||
}
|
||||
|
||||
if (!Container.has(StripeHelper)) {
|
||||
throw internalValidationError(
|
||||
throw AppError.internalValidationError(
|
||||
'PlaySubscriptions',
|
||||
{},
|
||||
new Error(
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Firestore } from '@google-cloud/firestore';
|
||||
import { Container } from 'typedi';
|
||||
import { TypedCollectionReference } from '@fxa/vendored/typesafe-node-firestore';
|
||||
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { AppConfig, AuthFirestore, AuthLogger } from '../../types';
|
||||
import { IapConfig } from './types';
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
TransactionSearchOptions,
|
||||
TransactionStatus,
|
||||
} from '@fxa/payments/paypal';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { CurrencyHelper } from '../currencies';
|
||||
import { StripeHelper } from '../stripe';
|
||||
import { RefusedError } from './error';
|
||||
@@ -525,7 +525,7 @@ export class PayPalHelper {
|
||||
try {
|
||||
[transactionResponse] = (await Promise.all(promises)) as [
|
||||
ChargeResponse,
|
||||
any
|
||||
any,
|
||||
];
|
||||
} catch (err) {
|
||||
if (PayPalClientError.hasPayPalNVPError(err) && !batchProcessing) {
|
||||
@@ -672,14 +672,19 @@ export class PayPalHelper {
|
||||
/**
|
||||
* Refunds the invoice passed, throwing an error on any issue encountered.
|
||||
*/
|
||||
public async refundInvoice(invoice: Stripe.Invoice, behavior: {
|
||||
refundType: RefundType.Full,
|
||||
} | {
|
||||
refundType: RefundType.Partial,
|
||||
amount: number
|
||||
} = {
|
||||
refundType: RefundType.Full,
|
||||
}) {
|
||||
public async refundInvoice(
|
||||
invoice: Stripe.Invoice,
|
||||
behavior:
|
||||
| {
|
||||
refundType: RefundType.Full;
|
||||
}
|
||||
| {
|
||||
refundType: RefundType.Partial;
|
||||
amount: number;
|
||||
} = {
|
||||
refundType: RefundType.Full,
|
||||
}
|
||||
) {
|
||||
this.log.debug('PayPalHelper.refundInvoice', {
|
||||
invoiceId: invoice.id,
|
||||
});
|
||||
@@ -707,12 +712,25 @@ export class PayPalHelper {
|
||||
throw new RefundError('Invoice already refunded with PayPal');
|
||||
}
|
||||
|
||||
if (behavior.refundType === RefundType.Partial && behavior.amount >= invoice.amount_paid) {
|
||||
throw new RefundError('Partial refunds must be less than the amount paid on the invoice');
|
||||
if (
|
||||
behavior.refundType === RefundType.Partial &&
|
||||
behavior.amount >= invoice.amount_paid
|
||||
) {
|
||||
throw new RefundError(
|
||||
'Partial refunds must be less than the amount paid on the invoice'
|
||||
);
|
||||
}
|
||||
const amount = behavior.refundType === RefundType.Partial ? behavior.amount : undefined;
|
||||
const amount =
|
||||
behavior.refundType === RefundType.Partial
|
||||
? behavior.amount
|
||||
: undefined;
|
||||
|
||||
await this.issueRefund(invoice, transactionId, behavior.refundType, amount);
|
||||
await this.issueRefund(
|
||||
invoice,
|
||||
transactionId,
|
||||
behavior.refundType,
|
||||
amount
|
||||
);
|
||||
|
||||
this.log.info('refundInvoice', {
|
||||
invoiceId: invoice.id,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Container } from 'typedi';
|
||||
|
||||
import { PayPalClientError } from '@fxa/payments/paypal';
|
||||
import { ConfigType } from '../../../config';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { StripeWebhookHandler } from '../../routes/subscriptions/stripe-webhook';
|
||||
import { reportSentryError } from '../../sentry';
|
||||
import { AuthLogger } from '../../types';
|
||||
|
||||
@@ -61,7 +61,7 @@ import { Stripe } from 'stripe';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import { ConfigType } from '../../config';
|
||||
import error from '../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { GoogleMapsService } from '../google-maps-services';
|
||||
import Redis from '../redis';
|
||||
import { subscriptionProductMetadataValidator } from '../routes/validators';
|
||||
@@ -2181,7 +2181,7 @@ export class StripeHelper extends StripeHelperBase {
|
||||
subscriptionId
|
||||
);
|
||||
if (!subscription) {
|
||||
throw error.unknownSubscription();
|
||||
throw error.unknownSubscription(subscriptionId);
|
||||
}
|
||||
|
||||
await this.updateSubscriptionAndBackfill(subscription, {
|
||||
@@ -2213,7 +2213,7 @@ export class StripeHelper extends StripeHelperBase {
|
||||
subscriptionId
|
||||
);
|
||||
if (!subscription) {
|
||||
throw error.unknownSubscription();
|
||||
throw error.unknownSubscription(subscriptionId);
|
||||
}
|
||||
|
||||
if (!ACTIVE_SUBSCRIPTION_STATUSES.includes(subscription.status)) {
|
||||
@@ -3545,8 +3545,10 @@ export class StripeHelper extends StripeHelperBase {
|
||||
* Process a invoice event that needs to be saved to Firestore.
|
||||
*/
|
||||
async processInvoiceEventToFirestore(event: Stripe.Event) {
|
||||
if (event.data.object.object !== "invoice") {
|
||||
throw new Error("processInvoiceEventToFirestore must receive only invoice types");
|
||||
if (event.data.object.object !== 'invoice') {
|
||||
throw new Error(
|
||||
'processInvoiceEventToFirestore must receive only invoice types'
|
||||
);
|
||||
}
|
||||
const eventData = event.data.object;
|
||||
|
||||
@@ -3554,15 +3556,21 @@ export class StripeHelper extends StripeHelperBase {
|
||||
if (!invoiceId) throw new Error('Invoice ID must be specified');
|
||||
const customerId = eventData.customer;
|
||||
if (typeof customerId !== 'string') {
|
||||
throw new Error("customerId must be a string");
|
||||
throw new Error('customerId must be a string');
|
||||
}
|
||||
|
||||
try {
|
||||
await this.stripeFirestore.fetchAndInsertInvoice(invoiceId, event.created);
|
||||
await this.stripeFirestore.fetchAndInsertInvoice(
|
||||
invoiceId,
|
||||
event.created
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.name === FirestoreStripeError.FIRESTORE_CUSTOMER_NOT_FOUND) {
|
||||
await this.stripeFirestore.fetchAndInsertCustomer(customerId);
|
||||
await this.stripeFirestore.fetchAndInsertInvoice(invoiceId, event.created);
|
||||
await this.stripeFirestore.fetchAndInsertInvoice(
|
||||
invoiceId,
|
||||
event.created
|
||||
);
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
@@ -3586,7 +3594,10 @@ export class StripeHelper extends StripeHelperBase {
|
||||
const paymentMethodId = (event.data.object as Stripe.PaymentMethod).id;
|
||||
|
||||
try {
|
||||
await this.stripeFirestore.fetchAndInsertPaymentMethod(paymentMethodId, event.created);
|
||||
await this.stripeFirestore.fetchAndInsertPaymentMethod(
|
||||
paymentMethodId,
|
||||
event.created
|
||||
);
|
||||
} catch (err) {
|
||||
if (
|
||||
!(
|
||||
|
||||
@@ -20,7 +20,7 @@ import { StatsD } from 'hot-shots';
|
||||
import { performance } from 'perf_hooks';
|
||||
|
||||
import { ConfigType } from '../../config';
|
||||
import error from '../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { PushboxDB } from './db';
|
||||
|
||||
// Pushbox stores strings, so these are a little pair
|
||||
|
||||
@@ -22,7 +22,7 @@ import MISC_DOCS from '../../docs/swagger/misc-api';
|
||||
import DESCRIPTION from '../../docs/swagger/shared/descriptions';
|
||||
import authMethods from '../authMethods';
|
||||
import random from '../crypto/random';
|
||||
import error from '../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { getClientById } from '../oauth/client';
|
||||
import { generateAccessToken } from '../oauth/grant';
|
||||
import jwt from '../oauth/jwt';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const isA = require('joi');
|
||||
const validators = require('./validators');
|
||||
const authorizedClients = require('../oauth/authorized_clients');
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
const HEX_STRING = validators.HEX_STRING;
|
||||
const DEVICES_SCHEMA = require('../devices').schema;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const AppError = require('../../error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const token = require('../../oauth/token');
|
||||
|
||||
const authName = 'fxa-oauth';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { OAuth2Client } from 'google-auth-library';
|
||||
import { Request, ResponseToolkit } from '@hapi/hapi';
|
||||
import AppError from '../../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
|
||||
export const strategy = ({
|
||||
aud,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const AppError = require('../../error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const Boom = require('@hapi/boom');
|
||||
|
||||
// The following regexes and Hawk header parsing are taken from the Hawk library.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { Request, ResponseToolkit } from '@hapi/hapi';
|
||||
import * as AppError from '../../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import { ConfigType } from '../../../config/index';
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
import { Account } from 'fxa-shared/db/models/auth';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const AppError = require('../../error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const joi = require('joi');
|
||||
const validators = require('../validators');
|
||||
const { BEARER_AUTH_REGEX } = validators;
|
||||
@@ -26,15 +26,14 @@ module.exports = function schemeRefreshTokenScheme(config, db) {
|
||||
return {
|
||||
async authenticate(request, h) {
|
||||
if (config.oauth.deviceAccessEnabled === false) {
|
||||
throw new AppError.featureNotEnabled();
|
||||
throw AppError.featureNotEnabled();
|
||||
}
|
||||
|
||||
const bearerMatch = BEARER_AUTH_REGEX.exec(
|
||||
request.headers.authorization
|
||||
);
|
||||
const bearerMatchErr = new AppError.invalidRequestParameter(
|
||||
'authorization'
|
||||
);
|
||||
const bearerMatchErr =
|
||||
AppError.invalidRequestParameter('authorization');
|
||||
const bearerToken = bearerMatch && bearerMatch[1];
|
||||
if (bearerToken) {
|
||||
joi.attempt(bearerMatch[1], validators.refreshToken, bearerMatchErr);
|
||||
@@ -45,7 +44,7 @@ module.exports = function schemeRefreshTokenScheme(config, db) {
|
||||
const tokenId = encrypt.hash(bearerToken);
|
||||
const refreshToken = await oauthDB.getRefreshToken(tokenId);
|
||||
if (!refreshToken) {
|
||||
return h.unauthenticated(new AppError.invalidToken());
|
||||
return h.unauthenticated(AppError.invalidToken());
|
||||
}
|
||||
if (
|
||||
!refreshToken.scope.intersects(ALLOWED_REFRESH_TOKEN_SCHEME_SCOPES)
|
||||
@@ -71,7 +70,7 @@ module.exports = function schemeRefreshTokenScheme(config, db) {
|
||||
|
||||
credentials.client = await client.getClientById(refreshToken.clientId);
|
||||
if (!credentials.client || !credentials.client.publicClient) {
|
||||
return h.unauthenticated(new AppError.notPublicClient());
|
||||
return h.unauthenticated(AppError.notPublicClient());
|
||||
}
|
||||
const devices = await db.devices(credentials.uid);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Boom = require('@hapi/boom');
|
||||
const AppError = require('../../error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const constantTimeCompare = (subject, object) => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const AppError = require('../../error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const authMethods = require('../../authMethods');
|
||||
const { parseAuthorizationHeader } = require('./hawk-fxa-token');
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import crypto from 'crypto';
|
||||
import { ConfigType } from '../../config';
|
||||
import { AuthLogger, AuthRequest } from '../types';
|
||||
import { Container } from 'typedi';
|
||||
import AppError from '../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import isA from 'joi';
|
||||
import validators from './validators';
|
||||
import { StatsD } from 'hot-shots';
|
||||
@@ -28,7 +28,12 @@ export class CMSHandler {
|
||||
this.config = config;
|
||||
this.statsd = statsD;
|
||||
this.log = log;
|
||||
this.localization = new CMSLocalization(log, config, this.cmsManager, this.statsd);
|
||||
this.localization = new CMSLocalization(
|
||||
log,
|
||||
config,
|
||||
this.cmsManager,
|
||||
this.statsd
|
||||
);
|
||||
}
|
||||
|
||||
ensureCmsManager() {
|
||||
@@ -109,7 +114,7 @@ export class CMSHandler {
|
||||
this.log.info('cms.getLocalizedConfig.noBaseConfig', {
|
||||
clientId,
|
||||
entrypoint,
|
||||
locale
|
||||
locale,
|
||||
});
|
||||
return {};
|
||||
}
|
||||
@@ -120,33 +125,39 @@ export class CMSHandler {
|
||||
clientId,
|
||||
entrypoint,
|
||||
locale,
|
||||
reason: locale === 'en' ? 'default-locale' : 'localization-disabled'
|
||||
reason: locale === 'en' ? 'default-locale' : 'localization-disabled',
|
||||
});
|
||||
return baseConfig;
|
||||
}
|
||||
|
||||
// 4. Try to fetch localized FTL content with fallback logic
|
||||
const ftlContent = await this.localization.fetchLocalizedFtlWithFallback(locale);
|
||||
const ftlContent =
|
||||
await this.localization.fetchLocalizedFtlWithFallback(locale);
|
||||
|
||||
// 5. If no localized content, return base config
|
||||
if (!ftlContent) {
|
||||
this.log.info('cms.getLocalizedConfig.fallbackToBase', {
|
||||
clientId,
|
||||
entrypoint,
|
||||
locale
|
||||
locale,
|
||||
});
|
||||
this.statsd.increment('cms.getLocalizedConfig.fallback');
|
||||
return baseConfig;
|
||||
}
|
||||
|
||||
// 6. Merge base config with localized data
|
||||
const localizedConfig = await this.localization.mergeConfigs(baseConfig, ftlContent, clientId, entrypoint);
|
||||
const localizedConfig = await this.localization.mergeConfigs(
|
||||
baseConfig,
|
||||
ftlContent,
|
||||
clientId,
|
||||
entrypoint
|
||||
);
|
||||
|
||||
this.log.info('cms.getLocalizedConfig.success', {
|
||||
clientId,
|
||||
entrypoint,
|
||||
locale,
|
||||
ftlContentLength: ftlContent.length
|
||||
ftlContentLength: ftlContent.length,
|
||||
});
|
||||
this.statsd.increment('cms.getLocalizedConfig.success');
|
||||
|
||||
@@ -157,7 +168,7 @@ export class CMSHandler {
|
||||
clientId,
|
||||
entrypoint,
|
||||
locale,
|
||||
error: error.message
|
||||
error: error.message,
|
||||
});
|
||||
this.statsd.increment('cms.getLocalizedConfig.error');
|
||||
|
||||
@@ -169,7 +180,7 @@ export class CMSHandler {
|
||||
clientId,
|
||||
entrypoint,
|
||||
locale,
|
||||
error: fallbackError.message
|
||||
error: fallbackError.message,
|
||||
});
|
||||
return {};
|
||||
}
|
||||
@@ -223,7 +234,11 @@ export class CMSHandler {
|
||||
// Only create PRs when entries are actually published
|
||||
const allowedEvents = ['entry.publish'];
|
||||
|
||||
if (!eventType || !allowedEvents.includes(eventType) || webhookPayload.model !== 'relying-party') {
|
||||
if (
|
||||
!eventType ||
|
||||
!allowedEvents.includes(eventType) ||
|
||||
webhookPayload.model !== 'relying-party'
|
||||
) {
|
||||
this.log.info('cms.strapiWebhook.skipped', {
|
||||
eventType,
|
||||
reason: 'Event not in allowed list or not relying-party model',
|
||||
@@ -251,7 +266,8 @@ export class CMSHandler {
|
||||
await this.localization.validateGitHubConfig();
|
||||
|
||||
// Generate FTL content for all entries
|
||||
const ftlContent = this.localization.generateFtlContentFromEntries(allEntries);
|
||||
const ftlContent =
|
||||
this.localization.generateFtlContentFromEntries(allEntries);
|
||||
|
||||
// Check for existing PR
|
||||
const existingPr = await this.localization.findExistingPR(
|
||||
@@ -408,7 +424,7 @@ export const cmsRoutes = (
|
||||
},
|
||||
handler: async (request: AuthRequest) =>
|
||||
cmsHandler.handleCacheInvalidationWebhook(request),
|
||||
}
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
const getVersion = require('../version').getVersion;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const { URL } = require('url');
|
||||
const Ajv = require('ajv');
|
||||
const ajv = new Ajv();
|
||||
const hex = (v) => (Buffer.isBuffer(v) ? v.toString('hex') : v);
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const fs = require('fs');
|
||||
const isA = require('joi');
|
||||
const path = require('path');
|
||||
@@ -249,7 +249,7 @@ module.exports = (
|
||||
config.oauth.deviceCommandsEnabled === false &&
|
||||
credentials.refreshTokenId
|
||||
) {
|
||||
throw new error.featureNotEnabled();
|
||||
throw error.featureNotEnabled();
|
||||
}
|
||||
|
||||
if (!deviceId) {
|
||||
@@ -262,7 +262,7 @@ module.exports = (
|
||||
uaOSVersion: credentials.uaOSVersion,
|
||||
});
|
||||
|
||||
throw new error.unknownDevice();
|
||||
throw error.unknownDevice();
|
||||
}
|
||||
|
||||
const response = await pushbox.retrieve(uid, deviceId, limit, index);
|
||||
@@ -329,7 +329,7 @@ module.exports = (
|
||||
config.oauth.deviceCommandsEnabled === false &&
|
||||
credentials.refreshTokenId
|
||||
) {
|
||||
throw new error.featureNotEnabled();
|
||||
throw error.featureNotEnabled();
|
||||
}
|
||||
|
||||
await customs.checkAuthenticated(
|
||||
@@ -606,7 +606,7 @@ module.exports = (
|
||||
config.oauth.deviceCommandsEnabled === false &&
|
||||
credentials.refreshTokenId
|
||||
) {
|
||||
throw new error.featureNotEnabled();
|
||||
throw error.featureNotEnabled();
|
||||
}
|
||||
|
||||
// If this request is using a session token we bump the last access time
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
const butil = require('../crypto/butil');
|
||||
const emailUtils = require('./utils/email');
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const isA = require('joi');
|
||||
const random = require('../crypto/random');
|
||||
const Sentry = require('@sentry/node');
|
||||
|
||||
@@ -89,6 +89,10 @@ module.exports = function (
|
||||
statsd,
|
||||
glean
|
||||
);
|
||||
const oauthRoutes = oauth.map((route) => ({
|
||||
path: route.path,
|
||||
config: route.config || {},
|
||||
}));
|
||||
const devicesSessions = require('./devices-and-sessions')(
|
||||
log,
|
||||
db,
|
||||
@@ -305,6 +309,7 @@ module.exports = function (
|
||||
r.path = basePath + r.path;
|
||||
});
|
||||
const allRoutes = defaults.concat(idp, v1Routes);
|
||||
allRoutes.oauthRoutes = oauthRoutes;
|
||||
|
||||
allRoutes.forEach((r) => {
|
||||
// Default auth.payload to 'optional' for all authenticated routes.
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import THIRD_PARTY_AUTH_DOCS from '../../docs/swagger/third-party-auth-api';
|
||||
import isA from 'joi';
|
||||
import DESCRIPTION from '../../docs/swagger/shared/descriptions';
|
||||
import error from '../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { schema as METRICS_CONTEXT_SCHEMA } from '../metrics/context';
|
||||
import {
|
||||
getGooglePublicKey,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AuthRequest, SessionTokenAuthCredential } from '../types';
|
||||
import { recordSecurityEvent } from './utils/security-event';
|
||||
import { ConfigType } from '../../config';
|
||||
import { OtpUtils } from './utils/otp';
|
||||
import * as AppError from '../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
|
||||
/** Customs interface for mfa specific operations. */
|
||||
interface Customs {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const MISC_DOCS = require('../../docs/swagger/misc-api').default;
|
||||
const validators = require('./validators');
|
||||
const ScopeSet = require('fxa-shared/oauth/scopes').scopeSetHelpers;
|
||||
const AppError = require('../../lib/error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const Joi = require('joi');
|
||||
|
||||
const { OAUTH_SCOPE_NEWSLETTERS } = require('fxa-shared/oauth/constants');
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
const hex = (v) => (Buffer.isBuffer(v) ? v.toString('hex') : v);
|
||||
const Joi = require('joi');
|
||||
|
||||
const OauthError = require('../../oauth/error');
|
||||
const AuthError = require('../../error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const { AppError: AuthError } = require('@fxa/accounts/errors');
|
||||
const validators = require('../../oauth/validators');
|
||||
const { validateRequestedGrant, generateTokens } = require('../../oauth/grant');
|
||||
const { makeAssertionJWT } = require('../../oauth/util');
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
const Joi = require('joi');
|
||||
|
||||
const AppError = require('../../../oauth/error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const validators = require('../../../oauth/validators');
|
||||
const DESCRIPTION =
|
||||
require('../../../../docs/swagger/shared/descriptions').default;
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
const crypto = require('crypto');
|
||||
const Joi = require('joi');
|
||||
|
||||
const OauthError = require('../../oauth/error');
|
||||
const AuthError = require('../../error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const { AppError: AuthError } = require('@fxa/accounts/errors');
|
||||
const encrypt = require('fxa-shared/auth/encrypt');
|
||||
const validators = require('../../oauth/validators');
|
||||
const { getTokenId } = require('../../oauth/token');
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/*jshint camelcase: false*/
|
||||
const Joi = require('joi');
|
||||
const validators = require('../../oauth/validators');
|
||||
const AppError = require('../../oauth/error');
|
||||
const { AppError } = require('@fxa/accounts/errors');
|
||||
const { getTokenId } = require('../../oauth/token');
|
||||
const OAUTH_SERVER_DOCS =
|
||||
require('../../../docs/swagger/oauth-server-api').default;
|
||||
@@ -79,7 +79,7 @@ module.exports = ({ oauthDB }) => ({
|
||||
// in the future other clients should be able to use it
|
||||
// by providing client_secret in the Authentication header
|
||||
if (!client || !client.publicClient) {
|
||||
throw new AppError.notPublicClient();
|
||||
throw AppError.oauthNotPublicClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Joi = require('joi');
|
||||
const OauthError = require('../../oauth/error');
|
||||
const AuthError = require('../../error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const { AppError: AuthError } = require('@fxa/accounts/errors');
|
||||
const config = require('../../../config').default.getProperties();
|
||||
const validators = require('../../oauth/validators');
|
||||
const verifyAssertion = require('../../oauth/assertion');
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
/*jshint camelcase: false*/
|
||||
const crypto = require('crypto');
|
||||
const OauthError = require('../../oauth/error');
|
||||
const AuthError = require('../../error');
|
||||
const { OauthError } = require('@fxa/accounts/errors');
|
||||
const { AppError: AuthError } = require('@fxa/accounts/errors');
|
||||
const buf = (v) => (Buffer.isBuffer(v) ? v : Buffer.from(v, 'hex'));
|
||||
const hex = (v) => (Buffer.isBuffer(v) ? v.toString('hex') : v);
|
||||
const Joi = require('joi');
|
||||
|
||||
@@ -14,7 +14,7 @@ import PASSWORD_DOCS from '../../docs/swagger/password-api';
|
||||
import DESCRIPTION from '../../docs/swagger/shared/descriptions';
|
||||
import * as butil from '../crypto/butil';
|
||||
import * as random from '../crypto/random';
|
||||
import * as error from '../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { schema as METRICS_CONTEXT_SCHEMA } from '../metrics/context';
|
||||
import { gleanMetrics } from '../metrics/glean';
|
||||
import * as requestHelper from '../routes/utils/request_helper';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const errors = require('../error');
|
||||
const { AppError: errors } = require('@fxa/accounts/errors');
|
||||
const isA = require('joi');
|
||||
const validators = require('./validators');
|
||||
const { Container } = require('typedi');
|
||||
|
||||
@@ -8,8 +8,7 @@ const RECOVERY_KEY_DOCS =
|
||||
require('../../docs/swagger/recovery-key-api').default;
|
||||
const DESCRIPTION = require('../../docs/swagger/shared/descriptions').default;
|
||||
|
||||
const AppError = require('../error');
|
||||
const errors = require('../error');
|
||||
const { AppError: errors } = require('@fxa/accounts/errors');
|
||||
const { recordSecurityEvent } = require('./utils/security-event');
|
||||
const validators = require('./validators');
|
||||
const isA = require('joi');
|
||||
@@ -149,7 +148,7 @@ module.exports = (
|
||||
// if we are not explicitly requesting a key change
|
||||
// but an enabled key exists, throw an error
|
||||
} else if (enabledKey.exists && replaceKey !== true) {
|
||||
throw AppError.recoveryKeyExists();
|
||||
throw errors.recoveryKeyExists();
|
||||
} else {
|
||||
// if no key is enabled, attempt to create a new key
|
||||
await db.createRecoveryKey(
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
SessionTokenAuthCredential,
|
||||
} from '../types';
|
||||
import { E164_NUMBER } from './validators';
|
||||
import AppError from '../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import Localizer from '../l10n';
|
||||
import NodeRendererBindings from '../senders/renderer/bindings-node';
|
||||
import { AccountEventsManager } from '../account-events';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const isA = require('joi');
|
||||
const requestHelper = require('../routes/utils/request_helper');
|
||||
const METRICS_CONTEXT_SCHEMA = require('../metrics/context').schema;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { OAUTH_SCOPE_SUBSCRIPTIONS_IAP } from 'fxa-shared/oauth/constants';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import SUBSCRIPTIONS_DOCS from '../../../docs/swagger/subscriptions-api';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { CapabilityService } from '../../payments/capability';
|
||||
import { AppleIAP } from '../../payments/iap/apple-app-store/apple-iap';
|
||||
import { PurchaseUpdateError } from '../../payments/iap/apple-app-store/types/errors';
|
||||
|
||||
@@ -6,7 +6,7 @@ import isA from 'joi';
|
||||
import { OAUTH_SCOPE_SUBSCRIPTIONS_IAP } from 'fxa-shared/oauth/constants';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { CapabilityService } from '../../payments/capability';
|
||||
import { PlayBilling } from '../../payments/iap/google-play/play-billing';
|
||||
import { PurchaseUpdateError } from '../../payments/iap/google-play/types/errors';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Container } from 'typedi';
|
||||
import SUBSCRIPTIONS_DOCS from '../../../docs/swagger/subscriptions-api';
|
||||
import { AppStoreSubscriptions } from '../../../lib/payments/iap/apple-app-store/subscriptions';
|
||||
import { PlaySubscriptions } from '../../../lib/payments/iap/google-play/subscriptions';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import {
|
||||
appStoreSubscriptionPurchaseToAppStoreSubscriptionDTO,
|
||||
playStoreSubscriptionPurchaseToPlayStoreSubscriptionDTO,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import Stripe from 'stripe';
|
||||
|
||||
import { ConfigType } from '../../../config';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import {
|
||||
IpnMerchPmtType,
|
||||
isIpnMerchPmt,
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Stripe } from 'stripe';
|
||||
import Container from 'typedi';
|
||||
|
||||
import { ConfigType } from '../../../config';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { PayPalHelper } from '../../payments/paypal/helper';
|
||||
import { StripeHelper } from '../../payments/stripe';
|
||||
import { reportSentryError } from '../../sentry';
|
||||
|
||||
@@ -6,7 +6,7 @@ import isA from 'joi';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import SUBSCRIPTIONS_DOCS from '../../../docs/swagger/subscriptions-api';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { CapabilityService } from '../../payments/capability';
|
||||
import { PlayBilling } from '../../payments/iap/google-play/play-billing';
|
||||
import { DeveloperNotification } from '../../payments/iap/google-play/types';
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
reportSentryMessage,
|
||||
reportValidationError,
|
||||
} from '../../../lib/sentry';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { PayPalHelper, RefusedError } from '../../payments/paypal';
|
||||
import { RefundType } from '@fxa/payments/paypal';
|
||||
import {
|
||||
@@ -949,7 +949,7 @@ export class StripeWebhookHandler extends StripeHandler {
|
||||
{
|
||||
acceptLanguage: account.locale,
|
||||
...invoiceDetails,
|
||||
email: account.primaryEmail
|
||||
email: account.primaryEmail,
|
||||
}
|
||||
);
|
||||
await this.stripeHelper.updateEmailSent(invoice, 'paymentFailed');
|
||||
@@ -971,7 +971,7 @@ export class StripeWebhookHandler extends StripeHandler {
|
||||
{
|
||||
acceptLanguage: account.locale,
|
||||
...invoiceDetails,
|
||||
email: account.primaryEmail
|
||||
email: account.primaryEmail,
|
||||
},
|
||||
];
|
||||
switch (invoice.billing_reason) {
|
||||
@@ -1085,7 +1085,7 @@ export class StripeWebhookHandler extends StripeHandler {
|
||||
{
|
||||
acceptLanguage: account.locale,
|
||||
...invoiceDetails,
|
||||
email: account.primaryEmail
|
||||
email: account.primaryEmail,
|
||||
}
|
||||
);
|
||||
} else if (!subscription.cancel_at_period_end) {
|
||||
@@ -1100,7 +1100,7 @@ export class StripeWebhookHandler extends StripeHandler {
|
||||
...invoiceDetails,
|
||||
showOutstandingBalance,
|
||||
cancelAtEnd: subscription.cancel_at_period_end,
|
||||
email: account.primaryEmail
|
||||
email: account.primaryEmail,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ import assertNotNull from 'assert';
|
||||
import isA from 'joi';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { SeverityLevel } from '@sentry/core';
|
||||
import {
|
||||
CustomerError,
|
||||
PromotionCodeManager,
|
||||
} from '@fxa/payments/customer';
|
||||
import { CustomerError, PromotionCodeManager } from '@fxa/payments/customer';
|
||||
import { getAccountCustomerByUid } from 'fxa-shared/db/models/auth';
|
||||
import {
|
||||
AbbrevPlan,
|
||||
@@ -34,7 +31,7 @@ import { Logger } from 'mozlog';
|
||||
import { Stripe } from 'stripe';
|
||||
|
||||
import { ConfigType } from '../../../config';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import {
|
||||
COUNTRIES_LONG_NAME_TO_SHORT_NAME_MAP,
|
||||
StripeHelper,
|
||||
@@ -235,7 +232,7 @@ export class StripeHandler {
|
||||
subscriptionId
|
||||
);
|
||||
if (!subscription) {
|
||||
throw error.unknownSubscription();
|
||||
throw error.unknownSubscription(subscriptionId);
|
||||
}
|
||||
|
||||
const currentPlan = singlePlan(subscription);
|
||||
@@ -268,8 +265,9 @@ export class StripeHandler {
|
||||
const { amount: planAmount, currency: planCurrency } =
|
||||
await this.stripeHelper.findAbbrevPlanById(planId);
|
||||
assertNotNull(planAmount, 'planAmount');
|
||||
if (customer && customer.currency !== planCurrency) {
|
||||
throw error.currencyCurrencyMismatch(customer.currency, planCurrency);
|
||||
const customerCurrency = customer?.currency || undefined;
|
||||
if (customerCurrency && customerCurrency !== planCurrency) {
|
||||
throw error.currencyCurrencyMismatch(customerCurrency, planCurrency);
|
||||
}
|
||||
|
||||
// Update the plan
|
||||
@@ -359,7 +357,7 @@ export class StripeHandler {
|
||||
const plans = await this.stripeHelper.allAbbrevPlans();
|
||||
const planForProduct = plans.find((plan) => plan.product_id === productId);
|
||||
if (!planForProduct) {
|
||||
throw error.unknownSubscriptionPlan();
|
||||
throw error.unknownSubscriptionPlan(productId);
|
||||
}
|
||||
this.log.info('subscriptions.getProductName', {
|
||||
productId,
|
||||
|
||||
@@ -7,11 +7,10 @@ import zendesk from 'node-zendesk';
|
||||
import pRetry from 'p-retry';
|
||||
|
||||
import { ConfigType } from '../../../config';
|
||||
import error from '../../error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import { AuthLogger, AuthRequest } from '../../types';
|
||||
import { handleAuth } from './utils';
|
||||
import { email } from '../validators';
|
||||
import AppError from '../../error';
|
||||
|
||||
const MISC_DOCS = require('../../../docs/swagger/misc-api').default;
|
||||
|
||||
@@ -198,7 +197,7 @@ export const supportRoutes = (
|
||||
}
|
||||
return { success: true, ticket: createRequest.id };
|
||||
} catch (err) {
|
||||
throw error.backendServiceFailure(
|
||||
throw AppError.backendServiceFailure(
|
||||
'zendesk',
|
||||
operation,
|
||||
{ uid, email },
|
||||
|
||||
@@ -5,7 +5,7 @@ import { OAUTH_SCOPE_SUBSCRIPTIONS } from 'fxa-shared/oauth/constants';
|
||||
import ScopeSet from 'fxa-shared/oauth/scopes';
|
||||
import { Logger } from 'mozlog';
|
||||
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { AuthRequest, TaxAddress } from '../../types';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const errors = require('../error');
|
||||
const { AppError: errors } = require('@fxa/accounts/errors');
|
||||
const validators = require('./validators');
|
||||
const isA = require('joi');
|
||||
const otplib = require('otplib');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { StripeHelper } from '../../payments/stripe';
|
||||
import { AuthLogger, AuthRequest } from '../../types';
|
||||
import error from '../../error';
|
||||
import { AppError as error } from '@fxa/accounts/errors';
|
||||
import { reportSentryError } from '../../../lib/sentry';
|
||||
import { RelyingPartiesQuery } from '../../../../../libs/shared/cms/src/__generated__/graphql';
|
||||
import { RelyingPartyConfigurationManager } from '@fxa/shared/cms';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('../../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
const BOUNCE_ERRORS = new Set([
|
||||
error.ERRNO.BOUNCE_COMPLAINT,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { authenticator } from 'otplib';
|
||||
import { StatsD } from 'hot-shots';
|
||||
import errors from '../../error';
|
||||
import { AppError as errors } from '@fxa/accounts/errors';
|
||||
|
||||
export interface OtpDb {
|
||||
totpToken(uid: string): Promise<{ verified: boolean; enabled: boolean }>;
|
||||
|
||||
@@ -8,7 +8,7 @@ const emailUtils = require('./email');
|
||||
const isA = require('joi');
|
||||
const validators = require('../validators');
|
||||
const butil = require('../../crypto/butil');
|
||||
const error = require('../../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const { Container } = require('typedi');
|
||||
const { AccountEventsManager } = require('../../account-events');
|
||||
const { emailsMatch } = require('fxa-shared').email.helpers;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const Hoek = require('@hapi/hoek');
|
||||
const Sentry = require('@sentry/node');
|
||||
const verror = require('verror');
|
||||
const { ignoreErrors } = require('./error');
|
||||
const { ignoreErrors } = require('@fxa/accounts/errors');
|
||||
|
||||
const {
|
||||
formatMetadataValidationErrorMessage,
|
||||
|
||||
@@ -173,6 +173,7 @@ async function create(log, error, config, routes, db, statsd, glean, customs) {
|
||||
}
|
||||
|
||||
const server = new Hapi.Server(serverOptions);
|
||||
const oauthRoutes = routes.oauthRoutes || [];
|
||||
server.validator(require('joi'));
|
||||
|
||||
server.ext('onRequest', (request, h) => {
|
||||
@@ -337,7 +338,7 @@ async function create(log, error, config, routes, db, statsd, glean, customs) {
|
||||
translateStripeErrors(response);
|
||||
}
|
||||
|
||||
response = error.translate(request, response);
|
||||
response = error.translate(request, response, oauthRoutes);
|
||||
if (config.env !== 'prod') {
|
||||
response.backtrace(request.app.traced);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
const butil = require('../crypto/butil');
|
||||
const crypto = require('crypto');
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const hkdf = require('../crypto/hkdf');
|
||||
|
||||
const HASH_ALGORITHM = 'sha256';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const error = require('../error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
module.exports = (log, config) => {
|
||||
config = config || {};
|
||||
|
||||
@@ -6,7 +6,7 @@ import createClient from 'openapi-fetch';
|
||||
import { components, paths } from './identity-schema';
|
||||
|
||||
import { DB } from '../../lib/db';
|
||||
import { ERRNO } from '../../lib/error';
|
||||
import { ERRNO } from '@fxa/accounts/errors';
|
||||
import * as pbkdf2 from '../../lib/crypto/pbkdf2';
|
||||
import PasswordFn from '../../lib/crypto/password';
|
||||
import hkdf from '../../lib/crypto/hkdf';
|
||||
|
||||
@@ -20,7 +20,7 @@ const LIB_DIR = `${ROOT_DIR}/lib`;
|
||||
|
||||
const config = require(`${ROOT_DIR}/config`).default.getProperties();
|
||||
|
||||
const error = require(`${LIB_DIR}/error`);
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const log = require(`${LIB_DIR}/log`)(config.log);
|
||||
const jwt = require(`${LIB_DIR}/oauth/jwt`);
|
||||
const verificationReminders = require(`${LIB_DIR}/verification-reminders`)(
|
||||
@@ -30,8 +30,9 @@ const verificationReminders = require(`${LIB_DIR}/verification-reminders`)(
|
||||
const Sentry = require('@sentry/node');
|
||||
|
||||
const cadReminders = require(`${LIB_DIR}/cad-reminders`)(config, log);
|
||||
const subscriptionAccountReminders =
|
||||
require(`${LIB_DIR}/subscription-account-reminders`)(log, config);
|
||||
const subscriptionAccountReminders = require(
|
||||
`${LIB_DIR}/subscription-account-reminders`
|
||||
)(log, config);
|
||||
|
||||
Sentry.init({});
|
||||
const checkInId = Sentry.captureCheckIn({
|
||||
|
||||
@@ -9,7 +9,7 @@ const { default: Container } = require('typedi');
|
||||
const { AppConfig, AuthLogger } = require('../../lib/types');
|
||||
const mocks = require('../mocks');
|
||||
const uuid = require('uuid');
|
||||
const error = require('../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const {
|
||||
AppleIAP,
|
||||
} = require('../../lib/payments/iap/apple-app-store/apple-iap');
|
||||
|
||||
@@ -8,7 +8,7 @@ const sinon = require('sinon');
|
||||
const assert = { ...sinon.assert, ...require('chai').assert };
|
||||
|
||||
const mocks = require('../mocks');
|
||||
const error = require('../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
|
||||
const authMethods = require('../../lib/authMethods');
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const ROOT_DIR = '../..';
|
||||
const assert = require('assert');
|
||||
const config = require(`${ROOT_DIR}/config`).default.getProperties();
|
||||
const createBounces = require(`${ROOT_DIR}/lib/bounces`);
|
||||
const error = require(`${ROOT_DIR}/lib/error`);
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const sinon = require('sinon');
|
||||
|
||||
const EMAIL = Math.random() + '@example.test';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const sinon = require('sinon');
|
||||
const assert = { ...sinon.assert, ...require('chai').assert };
|
||||
const mocks = require('../mocks');
|
||||
const error = require(`../../lib/error.js`);
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const nock = require('nock');
|
||||
|
||||
const CUSTOMS_URL_REAL = 'http://localhost:7000';
|
||||
|
||||
@@ -9,7 +9,7 @@ const sinon = require('sinon');
|
||||
const proxyquire = require('proxyquire');
|
||||
const crypto = require('crypto');
|
||||
const mocks = require('../mocks');
|
||||
const error = require('../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const uuid = require('uuid');
|
||||
|
||||
describe('lib/devices:', () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ const ROOT_DIR = '../../..';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const bounces = require(`${ROOT_DIR}/lib/email/bounces`);
|
||||
const error = require(`${ROOT_DIR}/lib/error`);
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const { EventEmitter } = require('events');
|
||||
const { mockLog } = require('../../mocks');
|
||||
const sinon = require('sinon');
|
||||
@@ -428,7 +428,7 @@ describe('bounce messages', () => {
|
||||
|
||||
it('should log errors when deleting the email record', () => {
|
||||
mockDB.deleteAccount = sinon.spy(() =>
|
||||
Promise.reject(new error.unknownAccount('test@example.com'))
|
||||
Promise.reject(error.unknownAccount('test@example.com'))
|
||||
);
|
||||
const mockMsg = mockMessage({
|
||||
bounce: {
|
||||
@@ -461,7 +461,7 @@ describe('bounce messages', () => {
|
||||
mockDB.accountRecord = sinon.spy((email) => {
|
||||
// Lookup only succeeds when using original, unquoted email addr.
|
||||
if (email !== 'test.@example.com') {
|
||||
return Promise.reject(new error.unknownAccount(email));
|
||||
return Promise.reject(error.unknownAccount(email));
|
||||
}
|
||||
return Promise.resolve({
|
||||
createdAt: Date.now(),
|
||||
@@ -503,7 +503,7 @@ describe('bounce messages', () => {
|
||||
mockDB.accountRecord = sinon.spy((email) => {
|
||||
// Lookup only succeeds when using original, unquoted email addr.
|
||||
if (email !== 'test..me@example.com') {
|
||||
return Promise.reject(new error.unknownAccount(email));
|
||||
return Promise.reject(error.unknownAccount(email));
|
||||
}
|
||||
return Promise.resolve({
|
||||
createdAt: Date.now(),
|
||||
@@ -544,7 +544,7 @@ describe('bounce messages', () => {
|
||||
|
||||
it('should log a warning if it receives an unparseable email address', () => {
|
||||
mockDB.accountRecord = sinon.spy(() =>
|
||||
Promise.reject(new error.unknownAccount())
|
||||
Promise.reject(error.unknownAccount())
|
||||
);
|
||||
return mockedBounces(log, mockDB)
|
||||
.handleBounce(
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const ROOT_DIR = '../../..';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const error = require(`${ROOT_DIR}/lib/error`);
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const { mockLog } = require('../../mocks');
|
||||
const notifications = require(`${ROOT_DIR}/lib/email/notifications`);
|
||||
const sinon = require('sinon');
|
||||
|
||||
@@ -6,15 +6,21 @@
|
||||
|
||||
const { assert } = require('chai');
|
||||
const verror = require('verror');
|
||||
const AppError = require('../../lib/error');
|
||||
const OauthError = require('../../lib/oauth/error');
|
||||
const { AppError, OauthError } = require('@fxa/accounts/errors');
|
||||
|
||||
const mockOauthRoutes = [
|
||||
{
|
||||
path: '/token',
|
||||
config: { cors: true },
|
||||
},
|
||||
];
|
||||
|
||||
describe('AppErrors', () => {
|
||||
it('exported functions exist', () => {
|
||||
assert.equal(typeof AppError, 'function');
|
||||
assert.equal(AppError.length, 4);
|
||||
assert.equal(typeof AppError.translate, 'function');
|
||||
assert.lengthOf(AppError.translate, 2);
|
||||
assert.lengthOf(AppError.translate, 3);
|
||||
assert.equal(typeof AppError.invalidRequestParameter, 'function');
|
||||
assert.equal(AppError.invalidRequestParameter.length, 1);
|
||||
assert.equal(typeof AppError.missingRequestParameter, 'function');
|
||||
@@ -27,7 +33,8 @@ describe('AppErrors', () => {
|
||||
assert.equal(oauthError.errno, 104);
|
||||
const result = AppError.translate(
|
||||
{ route: { path: '/v1/oauth/token' } },
|
||||
oauthError
|
||||
oauthError,
|
||||
mockOauthRoutes
|
||||
);
|
||||
assert.ok(result instanceof AppError, 'instanceof AppError');
|
||||
assert.equal(result.errno, 110);
|
||||
@@ -38,7 +45,8 @@ describe('AppErrors', () => {
|
||||
assert.equal(oauthError.errno, 104);
|
||||
const result = AppError.translate(
|
||||
{ route: { path: '/v1/token' } },
|
||||
oauthError
|
||||
oauthError,
|
||||
mockOauthRoutes
|
||||
);
|
||||
assert.ok(result instanceof OauthError, 'instanceof OauthError');
|
||||
assert.equal(result.errno, 104);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import proxyquire from 'proxyquire';
|
||||
import sinon, { SinonStub } from 'sinon';
|
||||
import { assert } from 'chai';
|
||||
import AppError from '../../../lib/error';
|
||||
import { AppError } from '@fxa/accounts/errors';
|
||||
import mocks from '../../mocks';
|
||||
import { GleanMetricsType } from '../../../lib/metrics/glean';
|
||||
import { AuthRequest } from '../../../lib/types';
|
||||
@@ -192,12 +192,10 @@ const gleanProxy = proxyquire('../../../lib/metrics/glean', {
|
||||
recordTwoStepAuthPhoneReplaceSuccess,
|
||||
recordTwoStepAuthPhoneReplaceFailure:
|
||||
recordTwoStepAuthPhoneReplaceFailure,
|
||||
recordLoginConfirmSkipForKnownIp:
|
||||
recordLoginConfirmSkipForKnownIp,
|
||||
recordLoginConfirmSkipForNewAccount:
|
||||
recordLoginConfirmSkipForNewAccount,
|
||||
recordLoginConfirmSkipForKnownIp: recordLoginConfirmSkipForKnownIp,
|
||||
recordLoginConfirmSkipForNewAccount: recordLoginConfirmSkipForNewAccount,
|
||||
recordLoginConfirmSkipForKnownDevice:
|
||||
recordLoginConfirmSkipForKnownDevice,
|
||||
recordLoginConfirmSkipForKnownDevice,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ const {
|
||||
} = require('../../../../lib/payments/configuration/manager');
|
||||
const { setupFirestore } = require('../../../../lib/firestore-db');
|
||||
const { randomUUID } = require('crypto');
|
||||
const errors = require('../../../../lib/error');
|
||||
const { AppError: errors } = require('@fxa/accounts/errors');
|
||||
const {
|
||||
ProductConfig,
|
||||
} = require('fxa-shared/subscriptions/configuration/product');
|
||||
|
||||
@@ -12,7 +12,7 @@ const { PayPalHelper } = require('../../../lib/payments/paypal/helper');
|
||||
const { mockLog } = require('../../mocks');
|
||||
const { PaypalProcessor } = require('../../../lib/payments/paypal/processor');
|
||||
const { StripeHelper } = require('../../../lib/payments/stripe');
|
||||
const error = require('../../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const paidInvoice = require('./fixtures/stripe/invoice_paid.json');
|
||||
const unpaidInvoice = require('./fixtures/stripe/invoice_open.json');
|
||||
const customer1 = require('./fixtures/stripe/customer1.json');
|
||||
|
||||
@@ -19,7 +19,7 @@ const {
|
||||
} = require('@fxa/payments/paypal');
|
||||
const { PayPalHelper, RefusedError } = require('../../../lib/payments/paypal');
|
||||
const { mockLog } = require('../../mocks');
|
||||
const error = require('../../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const successfulSetExpressCheckoutResponse = require('./fixtures/paypal/set_express_checkout_success.json');
|
||||
const successfulDoReferenceTransactionResponse = require('./fixtures/paypal/do_reference_transaction_success.json');
|
||||
const successfulRefundTransactionResponse = require('./fixtures/paypal/refund_transaction_success.json');
|
||||
@@ -736,7 +736,8 @@ describe('PayPalHelper', () => {
|
||||
...validInvoice,
|
||||
amount_paid: 1000,
|
||||
};
|
||||
const expectedErrorMessage = 'Partial refunds must be less than the amount paid on the invoice';
|
||||
const expectedErrorMessage =
|
||||
'Partial refunds must be less than the amount paid on the invoice';
|
||||
mockStripeHelper.getInvoicePaypalTransactionId =
|
||||
sinon.fake.returns('123');
|
||||
mockStripeHelper.getInvoicePaypalRefundTransactionId =
|
||||
@@ -909,9 +910,8 @@ describe('PayPalHelper', () => {
|
||||
it('returns false with no billing agreement found', async () => {
|
||||
mockStripeHelper.getCustomerPaypalAgreement =
|
||||
sinon.fake.returns(undefined);
|
||||
const result = await paypalHelper.conditionallyRemoveBillingAgreement(
|
||||
mockCustomer
|
||||
);
|
||||
const result =
|
||||
await paypalHelper.conditionallyRemoveBillingAgreement(mockCustomer);
|
||||
assert.isFalse(result);
|
||||
});
|
||||
|
||||
@@ -921,9 +921,8 @@ describe('PayPalHelper', () => {
|
||||
mockCustomer.subscriptions = {
|
||||
data: [{ status: 'active', collection_method: 'send_invoice' }],
|
||||
};
|
||||
const result = await paypalHelper.conditionallyRemoveBillingAgreement(
|
||||
mockCustomer
|
||||
);
|
||||
const result =
|
||||
await paypalHelper.conditionallyRemoveBillingAgreement(mockCustomer);
|
||||
assert.isFalse(result);
|
||||
});
|
||||
|
||||
@@ -933,9 +932,8 @@ describe('PayPalHelper', () => {
|
||||
mockCustomer.subscriptions = { data: [] };
|
||||
paypalHelper.cancelBillingAgreement = sinon.fake.resolves({});
|
||||
mockStripeHelper.removeCustomerPaypalAgreement = sinon.fake.resolves({});
|
||||
const result = await paypalHelper.conditionallyRemoveBillingAgreement(
|
||||
mockCustomer
|
||||
);
|
||||
const result =
|
||||
await paypalHelper.conditionallyRemoveBillingAgreement(mockCustomer);
|
||||
assert.isTrue(result);
|
||||
sinon.assert.calledOnceWithExactly(
|
||||
mockStripeHelper.getCustomerPaypalAgreement,
|
||||
|
||||
@@ -12,7 +12,7 @@ const Chance = require('chance');
|
||||
const { setupAuthDatabase } = require('fxa-shared/db');
|
||||
const Knex = require('knex');
|
||||
const { mockLog, asyncIterable } = require('../../mocks');
|
||||
const error = require('../../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const stripeError = require('stripe').Stripe.errors;
|
||||
const uuidv4 = require('uuid').v4;
|
||||
const moment = require('moment');
|
||||
@@ -125,7 +125,6 @@ const {
|
||||
newFirestoreStripeError,
|
||||
StripeFirestoreMultiError,
|
||||
} = require('../../../lib/payments/stripe-firestore');
|
||||
const AppError = require('../../../lib/error');
|
||||
|
||||
const mockConfig = {
|
||||
authFirestore: {
|
||||
@@ -2034,7 +2033,7 @@ describe('#integration - StripeHelper', () => {
|
||||
...expectedTemplate,
|
||||
valid: false,
|
||||
};
|
||||
const err = new AppError('previewInvoiceFailed');
|
||||
const err = new error('previewInvoiceFailed');
|
||||
sandbox.stub(stripeHelper, 'previewInvoice').rejects(err);
|
||||
|
||||
sandbox.stub(stripeHelper, 'retrievePromotionCodeForPlan').resolves({
|
||||
@@ -4276,10 +4275,10 @@ describe('#integration - StripeHelper', () => {
|
||||
} catch (err) {
|
||||
thrown = err;
|
||||
}
|
||||
assert.isObject(thrown);
|
||||
assert.instanceOf(thrown, Error);
|
||||
assert.equal(thrown.message, 'System unavailable, try again soon');
|
||||
assert.equal(
|
||||
thrown.cause().message,
|
||||
thrown.jse_cause?.message,
|
||||
'Stripe Customer: cus_new has mismatched uid in metadata.'
|
||||
);
|
||||
});
|
||||
@@ -4589,7 +4588,7 @@ describe('#integration - StripeHelper', () => {
|
||||
thrown = err;
|
||||
}
|
||||
assert(stripeHelper.stripe.plans.list.calledOnce);
|
||||
assert.isObject(thrown);
|
||||
assert.instanceOf(thrown, Error);
|
||||
assert.equal(thrown.errno, error.ERRNO.UNKNOWN_SUBSCRIPTION_PLAN);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ const sandbox = sinon.createSandbox();
|
||||
|
||||
const { pushboxApi } = require('../../lib/pushbox');
|
||||
const pushboxDbModule = require('../../lib/pushbox/db');
|
||||
const error = require('../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const { mockLog } = require('../mocks');
|
||||
let mockStatsD;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ const {
|
||||
|
||||
const uuid = require('uuid');
|
||||
const crypto = require('crypto');
|
||||
const error = require('../../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const log = require('../../../lib/log');
|
||||
const otplib = require('otplib');
|
||||
const { Container } = require('typedi');
|
||||
@@ -946,7 +946,7 @@ describe('/account/create', () => {
|
||||
wrapWrapKb: 'wibble',
|
||||
},
|
||||
{
|
||||
emailRecord: new error.unknownAccount(),
|
||||
emailRecord: error.unknownAccount(),
|
||||
}
|
||||
);
|
||||
const mockMailer = mocks.mockMailer();
|
||||
@@ -1571,7 +1571,7 @@ describe('/account/stub', () => {
|
||||
wrapWrapKb: 'wibble',
|
||||
},
|
||||
{
|
||||
emailRecord: new error.unknownAccount(),
|
||||
emailRecord: error.unknownAccount(),
|
||||
}
|
||||
);
|
||||
const mockMailer = mocks.mockMailer();
|
||||
@@ -1712,7 +1712,7 @@ describe('/account/status', () => {
|
||||
},
|
||||
{
|
||||
...(shouldError && {
|
||||
emailRecord: new error.unknownAccount(),
|
||||
emailRecord: error.unknownAccount(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
@@ -1891,7 +1891,7 @@ describe('/account/finish_setup', () => {
|
||||
verifierSetAt: options.verifierSetAt,
|
||||
},
|
||||
{
|
||||
emailRecord: new error.unknownAccount(),
|
||||
emailRecord: error.unknownAccount(),
|
||||
}
|
||||
);
|
||||
const mockMailer = mocks.mockMailer();
|
||||
@@ -2043,7 +2043,7 @@ describe('/account/set_password', () => {
|
||||
verifierSetAt: options.verifierSetAt,
|
||||
},
|
||||
{
|
||||
emailRecord: new error.unknownAccount(),
|
||||
emailRecord: error.unknownAccount(),
|
||||
}
|
||||
);
|
||||
const mockMailer = mocks.mockMailer();
|
||||
@@ -4171,10 +4171,8 @@ describe('/account/login', () => {
|
||||
});
|
||||
|
||||
it('unknown account', () => {
|
||||
mockDB.accountRecord = () =>
|
||||
Promise.reject(new error.unknownAccount());
|
||||
mockDB.emailRecord = () =>
|
||||
Promise.reject(new error.unknownAccount());
|
||||
mockDB.accountRecord = () => Promise.reject(error.unknownAccount());
|
||||
mockDB.emailRecord = () => Promise.reject(error.unknownAccount());
|
||||
return runTest(route, mockRequestWithUnblockCode).then(
|
||||
() => assert(false),
|
||||
(err) => {
|
||||
|
||||
@@ -9,7 +9,7 @@ const assert = { ...sinon.assert, ...require('chai').assert };
|
||||
const crypto = require('crypto');
|
||||
const getRoute = require('../../routes_helpers').getRoute;
|
||||
const mocks = require('../../mocks');
|
||||
const error = require('../../../lib/error');
|
||||
const { AppError: error } = require('@fxa/accounts/errors');
|
||||
const proxyquire = require('proxyquire');
|
||||
const uuid = require('uuid');
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user