mirror of
https://github.com/wassname/talk.git
synced 2026-06-27 18:07:26 +08:00
[CORL-513] Permitted Domain Fixes (#2455)
* fix: adjusted allowed domains configuration * fix: removed unused logic around allowed domains prefixing * fix: removed unused localizations * fix: fixed signup flow
This commit is contained in:
Generated
+24
-8
@@ -2799,10 +2799,24 @@
|
||||
"url-regex": "~4.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ip-regex": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz",
|
||||
"integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0="
|
||||
},
|
||||
"normalize-url": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.2.0.tgz",
|
||||
"integrity": "sha512-WvF3Myk0NhXkG8S9bygFM4IC1KOvnVJGq0QoGeoqOYOBeinBZp5ybW3QuYbTc89lkWBMM9ZBO4QGRoc0353kKA=="
|
||||
},
|
||||
"url-regex": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/url-regex/-/url-regex-4.1.1.tgz",
|
||||
"integrity": "sha512-ViSDgDPNKkrQHI81GLCjdDN+Rsk3tAW/uLXlBOJxtcHzWZjta58Z0APXhfXzS89YszsheMnEvXeDXsWUB53wwA==",
|
||||
"requires": {
|
||||
"ip-regex": "^1.0.1",
|
||||
"tlds": "^1.187.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -18026,9 +18040,10 @@
|
||||
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
|
||||
},
|
||||
"ip-regex": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz",
|
||||
"integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0="
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-pKnZpbgCTfH/1NLIlOduP/V+WRXzC2MOz3Qo8xmxk8C5GudJLgK5QyLVXOSWy3ParAH7Eemurl3xjv/WXYFvMA==",
|
||||
"dev": true
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.6.0",
|
||||
@@ -33949,12 +33964,13 @@
|
||||
}
|
||||
},
|
||||
"url-regex": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/url-regex/-/url-regex-4.1.1.tgz",
|
||||
"integrity": "sha512-ViSDgDPNKkrQHI81GLCjdDN+Rsk3tAW/uLXlBOJxtcHzWZjta58Z0APXhfXzS89YszsheMnEvXeDXsWUB53wwA==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-regex/-/url-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-O08GjTiAFNsSlrUWfqF1jH0H1W3m35ZyadHrGv5krdnmPPoxP27oDTqux/579PtaroiSGm5yma6KT1mHFH6Y/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ip-regex": "^1.0.1",
|
||||
"tlds": "^1.187.0"
|
||||
"ip-regex": "^4.1.0",
|
||||
"tlds": "^1.203.0"
|
||||
}
|
||||
},
|
||||
"use": {
|
||||
|
||||
@@ -344,6 +344,7 @@
|
||||
"typeface-source-sans-pro": "^0.0.54",
|
||||
"typescript": "3.3.4000",
|
||||
"typescript-snapshots-plugin": "^1.6.0",
|
||||
"url-regex": "^5.0.0",
|
||||
"wait-for-expect": "^1.1.1",
|
||||
"webpack": "^4.30.0",
|
||||
"webpack-assets-manifest": "^3.1.1",
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
parseStringList,
|
||||
ValidationMessage,
|
||||
} from "coral-framework/lib/form";
|
||||
import { validateStrictURLList } from "coral-framework/lib/validation";
|
||||
import {
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
@@ -32,18 +33,21 @@ const PermittedDomainsConfig: FunctionComponent<Props> = ({ disabled }) => (
|
||||
</Header>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="configure-advanced-permittedDomains-explanation"
|
||||
id="configure-advanced-permittedDomains-description"
|
||||
strong={<strong />}
|
||||
>
|
||||
<Typography variant="detail">
|
||||
Domains where your Coral instance is allowed to be embedded. Typical
|
||||
use is localhost, staging.yourdomain.com, yourdomain.com, etc.
|
||||
The domains you would like to permit for Coral, e.g. your local,
|
||||
staging and production environments including the scheme (ex.
|
||||
http://localhost:3000, https://staging.domain.com,
|
||||
https://domain.com).
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Field
|
||||
name="allowedDomains"
|
||||
parse={parseStringList}
|
||||
format={formatStringList}
|
||||
validate={validateStrictURLList}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<>
|
||||
|
||||
@@ -299,9 +299,9 @@ each of your site’s stories.
|
||||
<p
|
||||
className="Box-root Typography-root Typography-detail Typography-colorTextPrimary"
|
||||
>
|
||||
Domains where your Coral instance is allowed to be embedded.
|
||||
Typical use is localhost, staging.yourdomain.com,
|
||||
yourdomain.com, etc.
|
||||
Domains where your Coral instance is allowed to be embedded
|
||||
including the scheme (ex. http://localhost:3000, https://staging.domain.com,
|
||||
https://domain.com).
|
||||
</p>
|
||||
<div
|
||||
className="TextField-root TextField-fullWidth"
|
||||
@@ -320,7 +320,7 @@ yourdomain.com, etc.
|
||||
placeholder=""
|
||||
spellCheck={false}
|
||||
type="text"
|
||||
value="localhost:8080"
|
||||
value="http://localhost:8080"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -216,8 +216,8 @@ it("change permitted domains to include more domains", async () => {
|
||||
Mutation: {
|
||||
updateSettings: ({ variables }) => {
|
||||
expectAndFail(variables.settings.allowedDomains).toEqual([
|
||||
"localhost:8080",
|
||||
"localhost:3000",
|
||||
"http://localhost:8080",
|
||||
"http://localhost:3000",
|
||||
]);
|
||||
return {
|
||||
settings: pureMerge(settings, variables.settings),
|
||||
@@ -238,7 +238,9 @@ it("change permitted domains to include more domains", async () => {
|
||||
);
|
||||
|
||||
// Let's change the permitted domains.
|
||||
permittedDomainsField.props.onChange("localhost:8080, localhost:3000");
|
||||
permittedDomainsField.props.onChange(
|
||||
"http://localhost:8080, http://localhost:3000"
|
||||
);
|
||||
|
||||
// Send form
|
||||
within(configureContainer)
|
||||
|
||||
@@ -50,7 +50,7 @@ export const settings = createFixture<GQLSettings>({
|
||||
enabled: true,
|
||||
},
|
||||
customCSSURL: "",
|
||||
allowedDomains: ["localhost:8080"],
|
||||
allowedDomains: ["http://localhost:8080"],
|
||||
editCommentWindowLength: 30000,
|
||||
communityGuidelines: {
|
||||
enabled: false,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createValidator } from "./validation";
|
||||
import { createValidator, validateStrictURLList } from "./validation";
|
||||
|
||||
describe("createValidator", () => {
|
||||
it("should report error when condition is unmet", () => {
|
||||
@@ -10,3 +10,25 @@ describe("createValidator", () => {
|
||||
expect(truthy(true, {})).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateStrictURLList", () => {
|
||||
it("should reject a URL without a scheme", () => {
|
||||
expect(validateStrictURLList(["localhost"], {})).toBeDefined();
|
||||
});
|
||||
|
||||
it("should reject multiple URLs without a scheme", () => {
|
||||
expect(
|
||||
validateStrictURLList(["http://localhost", "localhost"], {})
|
||||
).toBeDefined();
|
||||
});
|
||||
|
||||
it("should allow a URL with a scheme", () => {
|
||||
expect(validateStrictURLList(["http://localhost"], {})).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should allow multiple URLs with a scheme", () => {
|
||||
expect(
|
||||
validateStrictURLList(["http://localhost", "https://localhost"], {})
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,7 +58,8 @@ export function composeValidators<T = any, V = any>(
|
||||
* required is a Validator that checks that the value is truthy.
|
||||
*/
|
||||
export const required = createValidator(
|
||||
v => v !== "" && v !== null && v !== undefined,
|
||||
v =>
|
||||
Array.isArray(v) ? v.length > 0 : v !== "" && v !== null && v !== undefined,
|
||||
VALIDATION_REQUIRED()
|
||||
);
|
||||
|
||||
@@ -217,6 +218,28 @@ export const validatePercentage = (min: number, max: number) =>
|
||||
NOT_A_WHOLE_NUMBER_BETWEEN(min * 100, max * 100)
|
||||
);
|
||||
|
||||
export const validateStrictURLList = createValidator(v => {
|
||||
if (!Array.isArray(v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const url of v) {
|
||||
if (typeof url !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!URL_REGEX.test(url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!url.startsWith("http")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}, INVALID_URL());
|
||||
|
||||
/**
|
||||
* Condition represents a given check that can be performed for the purpose of
|
||||
* filtering a validation operation.
|
||||
|
||||
@@ -5,9 +5,12 @@ import { Field, Form } from "react-final-form";
|
||||
|
||||
import {
|
||||
colorFromMeta,
|
||||
formatStringList,
|
||||
OnSubmit,
|
||||
parseStringList,
|
||||
ValidationMessage,
|
||||
} from "coral-framework/lib/form";
|
||||
import { validateStrictURLList } from "coral-framework/lib/validation";
|
||||
import {
|
||||
Button,
|
||||
CallOut,
|
||||
@@ -23,7 +26,7 @@ import {
|
||||
import BackButton from "./BackButton";
|
||||
|
||||
interface FormProps {
|
||||
allowedDomains: string;
|
||||
allowedDomains: string[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@@ -34,9 +37,8 @@ interface Props {
|
||||
}
|
||||
|
||||
class PermittedDomainsStep extends Component<Props> {
|
||||
private onSubmit: OnSubmit<FormProps> = async (input, form) => {
|
||||
private onSubmit: OnSubmit<FormProps> = async ({ allowedDomains }, form) => {
|
||||
try {
|
||||
const allowedDomains = input.allowedDomains.split(",");
|
||||
await this.props.onInstall({ allowedDomains });
|
||||
return this.props.onGoToNextStep();
|
||||
} catch (error) {
|
||||
@@ -48,7 +50,7 @@ class PermittedDomainsStep extends Component<Props> {
|
||||
<Form
|
||||
onSubmit={this.onSubmit}
|
||||
initialValues={{
|
||||
allowedDomains: this.props.data.allowedDomains.join(","),
|
||||
allowedDomains: this.props.data.allowedDomains,
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
@@ -59,11 +61,12 @@ class PermittedDomainsStep extends Component<Props> {
|
||||
Permitted Domains
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Localized id="install-permittedDomains-description">
|
||||
<Localized id="install-permittedDomains-description-with-scheme">
|
||||
<Typography variant="bodyCopy" align="center">
|
||||
Enter the domains you would like to permit for Coral, e.g.
|
||||
your local, staging and production environments (ex.
|
||||
localhost:3000, staging.domain.com, domain.com).
|
||||
your local, staging and production environments including the
|
||||
scheme (ex. http://localhost:3000, https://staging.domain.com,
|
||||
https://domain.com).
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
@@ -73,7 +76,12 @@ class PermittedDomainsStep extends Component<Props> {
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field name="allowedDomains">
|
||||
<Field
|
||||
name="allowedDomains"
|
||||
parse={parseStringList}
|
||||
format={formatStringList}
|
||||
validate={validateStrictURLList}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-permittedDomains-permittedDomains">
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import url from "url-regex";
|
||||
|
||||
export const USERNAME_REGEX = new RegExp(/^[a-zA-Z0-9_.]+$/);
|
||||
export const USERNAME_MAX_LENGTH = 30;
|
||||
export const USERNAME_MIN_LENGTH = 3;
|
||||
@@ -6,9 +8,7 @@ export const PASSWORD_MIN_LENGTH = 8;
|
||||
|
||||
export const EMAIL_REGEX = new RegExp(/^\S+@\S+.\S+$/);
|
||||
|
||||
export const URL_REGEX = new RegExp(
|
||||
/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,5}(:[0-9]{1,5})?(\/.*)?$/
|
||||
);
|
||||
export const URL_REGEX = url({ exact: true, strict: true });
|
||||
|
||||
/**
|
||||
* ADDITIONAL_DETAILS_MAX_LENGTH defines the maximum length for the
|
||||
|
||||
@@ -35,7 +35,7 @@ const TenantInstallBodySchema = Joi.object().keys({
|
||||
allowedDomains: Joi.array().items(
|
||||
Joi.string()
|
||||
.trim()
|
||||
.uri()
|
||||
.uri({ scheme: ["http", "https"] })
|
||||
),
|
||||
locale: Joi.string()
|
||||
.default(null)
|
||||
|
||||
@@ -60,45 +60,3 @@ it("allows from the domain when it does provide a match and there are multiple t
|
||||
"allow-from https://news.coralproject.net"
|
||||
);
|
||||
});
|
||||
|
||||
it("it prefixes domains of the tenant when generating the frame option", () => {
|
||||
const tenant = {
|
||||
allowedDomains: ["coralproject.net", "news.coralproject.net"],
|
||||
};
|
||||
const req = {
|
||||
headers: {},
|
||||
query: { parentUrl: "http://news.coralproject.net/a/page" },
|
||||
} as Request;
|
||||
|
||||
expect(generateFrameOptions(req, tenant)).toEqual(
|
||||
"allow-from http://news.coralproject.net"
|
||||
);
|
||||
});
|
||||
|
||||
it("it prefixes domains of the tenant when generating the frame option", () => {
|
||||
const tenant = {
|
||||
allowedDomains: ["coralproject.net", "news.coralproject.net"],
|
||||
};
|
||||
const req = {
|
||||
headers: {},
|
||||
query: { parentUrl: "https://news.coralproject.net/a/page" },
|
||||
} as Request;
|
||||
|
||||
expect(generateFrameOptions(req, tenant)).toEqual(
|
||||
"allow-from https://news.coralproject.net"
|
||||
);
|
||||
});
|
||||
|
||||
it("it prefixes domains of the tenant when generating the frame option and denies based on it", () => {
|
||||
const tenant = {
|
||||
allowedDomains: ["coralproject.net", "news.coralproject.net"],
|
||||
};
|
||||
const req = {
|
||||
headers: {},
|
||||
query: { parentUrl: "http://news.coralproject.net/a/page" },
|
||||
} as Request;
|
||||
|
||||
expect(generateFrameOptions(req, tenant)).toEqual(
|
||||
"allow-from http://news.coralproject.net"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import builder from "content-security-policy-builder";
|
||||
import {
|
||||
doesRequireSchemePrefixing,
|
||||
extractParentsURL,
|
||||
getOrigin,
|
||||
isURLSecure,
|
||||
prefixSchemeIfRequired,
|
||||
} from "coral-server/app/url";
|
||||
import { extractParentsURL, getOrigin } from "coral-server/app/url";
|
||||
import { Tenant } from "coral-server/models/tenant";
|
||||
import { isURLPermitted } from "coral-server/services/tenant/url";
|
||||
import { Request, RequestHandler } from "coral-server/types/express";
|
||||
@@ -23,7 +17,7 @@ export const cspTenantMiddleware: RequestHandler = (req, res, next) => {
|
||||
|
||||
res.setHeader(
|
||||
"Content-Security-Policy",
|
||||
generateContentSecurityPolicy(req, tenant)
|
||||
generateContentSecurityPolicy(tenant)
|
||||
);
|
||||
|
||||
// Add some fallbacks for IE.
|
||||
@@ -33,10 +27,7 @@ export const cspTenantMiddleware: RequestHandler = (req, res, next) => {
|
||||
next();
|
||||
};
|
||||
|
||||
function generateContentSecurityPolicy(
|
||||
req: Request,
|
||||
tenant: Pick<Tenant, "allowedDomains">
|
||||
) {
|
||||
function generateContentSecurityPolicy(tenant: Pick<Tenant, "allowedDomains">) {
|
||||
const directives: Record<string, any> = {};
|
||||
|
||||
// Only the domains that are allowed by the tenant may embed Coral.
|
||||
@@ -58,12 +49,8 @@ export function generateFrameOptions(
|
||||
return "deny";
|
||||
}
|
||||
|
||||
// If there is only one domain on the tenant, and we don't require
|
||||
// prefixing, then return it!
|
||||
if (
|
||||
tenant.allowedDomains.length === 1 &&
|
||||
!doesRequireSchemePrefixing(tenant.allowedDomains[0])
|
||||
) {
|
||||
// If there is only one domain on the tenant then return it!
|
||||
if (tenant.allowedDomains.length === 1) {
|
||||
return `allow-from ${getOrigin(tenant.allowedDomains[0])}`;
|
||||
}
|
||||
|
||||
@@ -78,23 +65,6 @@ export function generateFrameOptions(
|
||||
return "deny";
|
||||
}
|
||||
|
||||
// Grab the status if the parent url is secure.
|
||||
const parentSecure = isURLSecure(parentsOrigin);
|
||||
if (parentSecure === null) {
|
||||
return "deny";
|
||||
}
|
||||
|
||||
// If there is only one domain on the tenant, and we require prefixing, then
|
||||
// return it with prefixing!
|
||||
if (
|
||||
tenant.allowedDomains.length === 1 &&
|
||||
!doesRequireSchemePrefixing(tenant.allowedDomains[0])
|
||||
) {
|
||||
return `allow-from ${getOrigin(
|
||||
prefixSchemeIfRequired(parentSecure, tenant.allowedDomains[0])
|
||||
)}`;
|
||||
}
|
||||
|
||||
// Determine if this origin is allowed.
|
||||
if (!isURLPermitted(tenant, parentsURL)) {
|
||||
return "deny";
|
||||
@@ -105,7 +75,7 @@ export function generateFrameOptions(
|
||||
// We need to find the domain that is asking so we can respond with the right
|
||||
// result, sort of like CORS!
|
||||
const allowFrom = tenant.allowedDomains
|
||||
.map(domain => getOrigin(prefixSchemeIfRequired(parentSecure, domain)))
|
||||
.map(domain => getOrigin(domain))
|
||||
.find(origin => origin === parentsOrigin);
|
||||
if (!allowFrom) {
|
||||
return "deny";
|
||||
|
||||
+25
-27
@@ -87,9 +87,9 @@ configure-permissionField-dontAllow = Ikke tilladt
|
||||
### General
|
||||
configure-general-guidelines-title = Oversigt over fællesskabsretningslinjer
|
||||
configure-general-guidelines-explanation =
|
||||
Skriv en oversigt over dine fællesskabsretningslinjer,
|
||||
der vises øverst i hver side af kommentarstrømmen.
|
||||
Dit resume kan formateres ved hjælp af Markdown Syntax.
|
||||
Skriv en oversigt over dine fællesskabsretningslinjer,
|
||||
der vises øverst i hver side af kommentarstrømmen.
|
||||
Dit resume kan formateres ved hjælp af Markdown Syntax.
|
||||
Mere information om hvordan du bruger Markdown kan findes
|
||||
<externalLink>her</externalLink>.
|
||||
configure-general-guidelines-showCommunityGuidelines = Vis oversigt over fællesskabsretningslinjer
|
||||
@@ -97,9 +97,9 @@ configure-general-guidelines-showCommunityGuidelines = Vis oversigt over fælles
|
||||
### Sitewide Commenting
|
||||
configure-general-sitewideCommenting-title = Kommentar på webstedet
|
||||
configure-general-sitewideCommenting-explanation =
|
||||
Åbn eller luk kommentarstrømme for nye kommentarer overalt.
|
||||
Når nye kommentarer deaktiveres overalt, kan nye kommentarer
|
||||
ikke indsendes, men eksisterende kommentarer kan fortsætte
|
||||
Åbn eller luk kommentarstrømme for nye kommentarer overalt.
|
||||
Når nye kommentarer deaktiveres overalt, kan nye kommentarer
|
||||
ikke indsendes, men eksisterende kommentarer kan fortsætte
|
||||
med at modtage reaktioner, rapporteres og deles.
|
||||
configure-general-sitewideCommenting-enableNewCommentsSitewide =
|
||||
Aktivér nye kommentarer overalt
|
||||
@@ -132,8 +132,8 @@ configure-general-commentLength-validateLongerThanMin =
|
||||
#### Comment Editing
|
||||
configure-general-commentEditing-title = Kommentarredigering
|
||||
configure-general-commentEditing-explanation =
|
||||
Sæt en grænse for, hvor længe kommentatorer skal redigere deres
|
||||
kommentarer på siden. Redigerede kommentarer markeres som (Redigeret)
|
||||
Sæt en grænse for, hvor længe kommentatorer skal redigere deres
|
||||
kommentarer på siden. Redigerede kommentarer markeres som (Redigeret)
|
||||
i kommentarstrømmen og moderationspanelet.
|
||||
configure-general-commentEditing-commentEditTimeFrame = Kommentar Rediger tidsramme
|
||||
configure-general-commentEditing-seconds = Sekunder
|
||||
@@ -148,8 +148,8 @@ configure-organization-nameExplanation =
|
||||
Dit organisationsnavn vises på e-mails sendt af { -product-name } til dit community og organisationsmedlemmer.
|
||||
configure-organization-email = Organisations-e-mail
|
||||
configure-organization-emailExplanation =
|
||||
Denne e-mail-adresse bruges som i e-mails og på tværs af platformen,
|
||||
hvor medlemmer af samfundet kan komme i kontakt med organisationen,
|
||||
Denne e-mail-adresse bruges som i e-mails og på tværs af platformen,
|
||||
hvor medlemmer af samfundet kan komme i kontakt med organisationen,
|
||||
hvis de har spørgsmål om status for deres konti eller moderationsspørgsmål.
|
||||
|
||||
### Email
|
||||
@@ -183,19 +183,19 @@ configure-auth-targetFilterCommentStream = Kommentarer
|
||||
configure-auth-redirectURI = Omdiriger URI
|
||||
configure-auth-registration = Registrering
|
||||
configure-auth-registrationDescription =
|
||||
Lad brugere, der ikke har tilmeldt sig tidligere med denne
|
||||
Lad brugere, der ikke har tilmeldt sig tidligere med denne
|
||||
godkendelsesintegration, registrere sig for en ny konto.
|
||||
configure-auth-registrationCheckBox = Tillad registrering
|
||||
configure-auth-pleaseEnableAuthForAdmin =
|
||||
Aktivér mindst én godkendelsesintegration til Administration af { -product-name }
|
||||
configure-auth-confirmNoAuthForCommentStream =
|
||||
Der er ikke aktiveret nogen godkendelsesintegration for kommentarstrømmen.
|
||||
Der er ikke aktiveret nogen godkendelsesintegration for kommentarstrømmen.
|
||||
Vil du virkelig fortsætte?
|
||||
|
||||
configure-auth-facebook-loginWith = Log ind med Facebook
|
||||
configure-auth-facebook-toEnableIntegration =
|
||||
For at aktivere integrationen med Facebook-godkendelse skal
|
||||
du oprette og konfigurere en webapplikation.
|
||||
For at aktivere integrationen med Facebook-godkendelse skal
|
||||
du oprette og konfigurere en webapplikation.
|
||||
For mere information besøg: <Link></Link>.
|
||||
configure-auth-facebook-useLoginOn = Brug Facebook til at logge på
|
||||
|
||||
@@ -225,9 +225,9 @@ configure-auth-oidc-providerNameDescription =
|
||||
Udbyderen af OpenID Connect-integrationen. Dette bruges, når udbyderens navn skal vises, f.eks. “Log ind med <Facebook>”.
|
||||
configure-auth-oidc-issuer = Udsteder
|
||||
configure-auth-oidc-issuerDescription =
|
||||
Når du har indtastet dine udstederoplysninger,
|
||||
Når du har indtastet dine udstederoplysninger,
|
||||
skal du klikke på knappen Opdag for at få { -product-name }
|
||||
til at udfylde de resterende felter. Du kan også
|
||||
til at udfylde de resterende felter. Du kan også
|
||||
indtaste oplysningerne manuelt.
|
||||
configure-auth-oidc-authorizationURL = Autoriserings-URL
|
||||
configure-auth-oidc-tokenURL = Token URL
|
||||
@@ -238,7 +238,7 @@ configure-auth-oidc-useLoginOn = Brug Open ID Connect til at logge på
|
||||
#### Pre-Moderation
|
||||
configure-moderation-preModeration-title = Pre-moderation
|
||||
configure-moderation-preModeration-explanation =
|
||||
Når pre-moderation er aktiveret, offentliggøres kommentarer ikke,
|
||||
Når pre-moderation er aktiveret, offentliggøres kommentarer ikke,
|
||||
medmindre de er godkendt af en moderator.
|
||||
configure-moderation-preModeration-moderation =
|
||||
Formoderer alle kommentarer overalt
|
||||
@@ -249,18 +249,18 @@ configure-moderation-apiKey = API-nøgle
|
||||
|
||||
configure-moderation-akismet-title = Akismet-spamdetekteringsfilter
|
||||
configure-moderation-akismet-explanation =
|
||||
Indsendte kommentarer videresendes til Akismet API til spamdetektion.
|
||||
Indsendte kommentarer videresendes til Akismet API til spamdetektion.
|
||||
Hvis en kommentar er bestemt til at være spam, vil den bede brugeren
|
||||
og indikere, at kommentaren kan betragtes som spam. Hvis brugeren
|
||||
fortsætter efter dette punkt med den stadig spam-lignende kommentar,
|
||||
markeres kommentaren som indeholdende spam, offentliggøres ikke og
|
||||
placeres i den ventende kø til gennemgang af en moderator.
|
||||
Hvis godkendt af en moderator, vil kommentaren blive offentliggjort.
|
||||
markeres kommentaren som indeholdende spam, offentliggøres ikke og
|
||||
placeres i den ventende kø til gennemgang af en moderator.
|
||||
Hvis godkendt af en moderator, vil kommentaren blive offentliggjort.
|
||||
|
||||
#### Akismet
|
||||
configure-moderation-akismet-filter = Spamdetekteringsfilter
|
||||
configure-moderation-akismet-accountNote =
|
||||
Bemærk: Du skal tilføje dit / de aktive domæner
|
||||
Bemærk: Du skal tilføje dit / de aktive domæner
|
||||
på din Akismet-konto: <externalLink>https://akismet.com/account/</externalLink>
|
||||
configure-moderation-akismet-siteURL = Hjemmeside URL
|
||||
|
||||
@@ -282,7 +282,7 @@ configure-moderation-perspective-toxicityThresholdDescription =
|
||||
ifølge Perspective API. Som standard er tærsklen indstillet til { $default }.
|
||||
configure-moderation-perspective-toxicityModel = Toksicitetsmodel
|
||||
cofigure-moderation-perspective-toxicityModelDescription =
|
||||
Vælg din perspektivmodel. Standard er { $default }.
|
||||
Vælg din perspektivmodel. Standard er { $default }.
|
||||
Du kan finde ud af mere om modelvalg <externalLink>her</externalLink>.
|
||||
configure-moderation-perspective-allowStoreCommentData = Tillad Google at gemme kommissionsdata
|
||||
configure-moderation-perspective-allowStoreCommentDataDescription =
|
||||
@@ -317,8 +317,6 @@ configure-advanced-customCSS-explanation =
|
||||
URL til et CSS-stilark, der tilsidesætter standardindlejring af streams. Kan være intern eller ekstern.
|
||||
|
||||
configure-advanced-permittedDomains = Tilladte domæner
|
||||
configure-advanced-permittedDomains-explanation =
|
||||
Domæner, hvor din forekomst af Coral må integreres. Typisk brug er localhost, staging.yourdomain.com, yourdomain.com osv.
|
||||
configure-advanced-liveUpdates = Kommentar Stream Live-opdateringer
|
||||
configure-advanced-liveUpdates-explanation =
|
||||
Når det er aktiveret, vil der blive realtid indlæst og opdateret af kommentarer, når nye kommentarer og svar offentliggøres.
|
||||
@@ -588,8 +586,8 @@ community-suspendModal-cancel = Afbestille
|
||||
community-suspendModal-suspendUser = Suspender bruger
|
||||
community-suspendModal-emailTemplate =
|
||||
Hej { $username },
|
||||
|
||||
I henhold til { $organizationName }'s community-retningslinjer er din konto midlertidigt suspenderet. Under suspensionen vil du ikke være i stand til at kommentere, markere eller samarbejde med andre kommentatorer. Genindgå samtalen om { framework-timeago-time }
|
||||
|
||||
I henhold til { $organizationName }'s community-retningslinjer er din konto midlertidigt suspenderet. Under suspensionen vil du ikke være i stand til at kommentere, markere eller samarbejde med andre kommentatorer. Genindgå samtalen om { framework-timeago-time }
|
||||
|
||||
community-suspendModal-customize = Tilpas suspension af e-mail-meddelelse
|
||||
|
||||
|
||||
@@ -340,10 +340,10 @@ configure-advanced-customCSS-explanation =
|
||||
URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.
|
||||
|
||||
configure-advanced-permittedDomains = Permitted Domains
|
||||
configure-advanced-permittedDomains-explanation =
|
||||
Domains where your { -product-name } instance is allowed to be embedded.
|
||||
Typical use is localhost, staging.yourdomain.com,
|
||||
yourdomain.com, etc.
|
||||
configure-advanced-permittedDomains-description =
|
||||
Domains where your { -product-name } instance is allowed to be embedded
|
||||
including the scheme (ex. http://localhost:3000, https://staging.domain.com,
|
||||
https://domain.com).
|
||||
|
||||
configure-advanced-liveUpdates = Comment Stream Live Updates
|
||||
configure-advanced-liveUpdates-explanation =
|
||||
@@ -723,7 +723,7 @@ invite-tokenNotFound =
|
||||
The specified link is invalid, check to see if it was copied correctly.
|
||||
|
||||
userDetails-banned-on = <strong>Banned on</strong> { $timestamp }
|
||||
userDetails-banned-by = <strong>by</strong> { $username }
|
||||
userDetails-banned-by = <strong>by</strong> { $username }
|
||||
userDetails-suspended-by = <strong>Suspended by</strong> { $username }
|
||||
userDetails-suspension-start = <strong>Start:</strong> { $timestamp }
|
||||
userDetails-suspension-end = <strong>End:</strong> { $timestamp }
|
||||
userDetails-suspension-end = <strong>End:</strong> { $timestamp }
|
||||
|
||||
@@ -41,7 +41,11 @@ install-createYourAccount-confirmPasswordTextField =
|
||||
|
||||
install-permittedDomains-stepTitle = Add Permitted Domains
|
||||
install-permittedDomains-title = Permitted Domains
|
||||
install-permittedDomains-description = Enter the domains you would like to permit for { -product-name }, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com).
|
||||
install-permittedDomains-description-with-scheme =
|
||||
Enter the domains you would like to permit for { -product-name }, e.g.
|
||||
your local, staging and production environments including the
|
||||
scheme (ex. http://localhost:3000, https://staging.domain.com,
|
||||
https://domain.com).
|
||||
install-permittedDomains-permittedDomains = Permitted Domains
|
||||
install-permittedDomains-permittedDomainsTextField =
|
||||
.placeholder = Domains
|
||||
|
||||
@@ -49,7 +49,7 @@ restricted-contactAdmin = Si cree que esto es un error, comuníquese con su admi
|
||||
login-signInTo = Registrarse en
|
||||
login-signIn-enterAccountDetailsBelow = Ingrese los detalles de su cuenta a continuación
|
||||
|
||||
login-emailAddressLabel = Correo electrónico
|
||||
login-emailAddressLabel = Correo electrónico
|
||||
login-emailAddressTextField =
|
||||
.placeholder = Correo electrónico
|
||||
|
||||
@@ -318,10 +318,6 @@ configure-advanced-customCSS-explanation =
|
||||
URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.
|
||||
|
||||
configure-advanced-permittedDomains = Permitted Domains
|
||||
configure-advanced-permittedDomains-explanation =
|
||||
Domains where your { -product-name } instance is allowed to be embedded.
|
||||
Typical use is localhost, staging.yourdomain.com,
|
||||
yourdomain.com, etc.
|
||||
|
||||
configure-advanced-liveUpdates = Comment Stream Live Updates
|
||||
configure-advanced-liveUpdates-explanation =
|
||||
|
||||
@@ -41,7 +41,6 @@ install-createYourAccount-confirmPasswordTextField =
|
||||
|
||||
install-permittedDomains-stepTitle = Agregar dominios permitidos
|
||||
install-permittedDomains-title = Dominios permitidos
|
||||
install-permittedDomains-description = Ingrese los dominios que desea permitir para {- nombre-producto}, p. sus entornos locales, de preparación y producción (por ejemplo, localhost: 3000, staging.domain.com, domain.com).
|
||||
install-permittedDomains-permittedDomains = Dominios permitidos
|
||||
install-permittedDomains-permittedDomainsTextField =
|
||||
.placeholder = Dominios
|
||||
|
||||
@@ -218,7 +218,7 @@ configure-auth-oidc-useLoginOn = Usar login com OpenID Connect ligado
|
||||
#### Pre-Moderation
|
||||
configure-moderation-preModeration-title = Pre-moderation
|
||||
configure-moderation-preModeration-explanation =
|
||||
Quando a pré-moderação está ativada, os comentários não serão publicados, a menos que sejam
|
||||
Quando a pré-moderação está ativada, os comentários não serão publicados, a menos que sejam
|
||||
aprovados por um moderador.
|
||||
configure-moderation-preModeration-moderation =
|
||||
Pré-moderar todos os comentários em todo o site
|
||||
@@ -298,10 +298,6 @@ configure-advanced-customCSS-explanation =
|
||||
URL de uma folha de estilo CSS que substituirá o estilo padrão dos fluxos de comentário das páginas. Pode ser interno ou externo.
|
||||
|
||||
configure-advanced-permittedDomains = Domínios Permitidos
|
||||
configure-advanced-permittedDomains-explanation =
|
||||
Domínios nos quais sua instância Coral pode ser incorporada.
|
||||
O uso típico é localhost, staging.yourdomain.com,
|
||||
yourdomain.com, etc.
|
||||
|
||||
configure-advanced-liveUpdates = Atualizações ao vivo do Stream de comentários
|
||||
configure-advanced-liveUpdates-explanation =
|
||||
@@ -514,15 +510,15 @@ community-invite-role-staff =
|
||||
ou mudar qualquer configuração { -product-name }.
|
||||
community-invite-role-moderator =
|
||||
<strong>Função Moderador:</strong> Recebe um crachá “Staff”, e
|
||||
seus comentários são aprovados automaticamente. Tem privilégios
|
||||
totais de moderação (aprovar, rejeitar e destacar comentários).
|
||||
seus comentários são aprovados automaticamente. Tem privilégios
|
||||
totais de moderação (aprovar, rejeitar e destacar comentários).
|
||||
Pode configurar artigos individuais, mas não possui privilégios
|
||||
de configuração do site.
|
||||
community-invite-role-admin =
|
||||
<strong>Função Admin:</strong> Recebe um crachá “Staff”, e
|
||||
seus comentários são aprovados automaticamente. Tem privilégios
|
||||
totais de moderação (aprovar, rejeitar e destacar comentários).
|
||||
Pode configurar artigos individuais e tem privilégios de
|
||||
seus comentários são aprovados automaticamente. Tem privilégios
|
||||
totais de moderação (aprovar, rejeitar e destacar comentários).
|
||||
Pode configurar artigos individuais e tem privilégios de
|
||||
configuração do site.
|
||||
community-invite-invitationsSent = Seus convites foram enviados!
|
||||
community-invite-close = Fechar
|
||||
|
||||
@@ -41,7 +41,6 @@ install-createYourAccount-confirmPasswordTextField =
|
||||
|
||||
install-permittedDomains-stepTitle = Adicionar domínios permitidos
|
||||
install-permittedDomains-title = Domínios Permitidos
|
||||
install-permittedDomains-description = Insira os domínios que você gostaria de permitir para Coral, por exemplo seus ambientes locais, de preparação e produção (ex. localhost: 3000, staging.domain.com, domain.com).
|
||||
install-permittedDomains-permittedDomains = Domínios Permitidos
|
||||
install-permittedDomains-permittedDomainsTextField =
|
||||
.placeholder = Domínios
|
||||
|
||||
Reference in New Issue
Block a user