diff --git a/app/components/crate-header.gjs b/app/components/crate-header.gjs
new file mode 100644
index 00000000000..b767bc60840
--- /dev/null
+++ b/app/components/crate-header.gjs
@@ -0,0 +1,115 @@
+import { LinkTo } from '@ember/routing';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+
+import { task } from 'ember-concurrency';
+import pluralize from 'ember-inflector/helpers/pluralize';
+import link_ from 'ember-link/helpers/link';
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+import { alias } from 'macro-decorators';
+
+import FollowButton from 'crates-io/components/follow-button';
+import NavTabs from 'crates-io/components/nav-tabs';
+import PageHeader from 'crates-io/components/page-header';
+import Tooltip from 'crates-io/components/tooltip';
+
+export default class CrateHeader extends Component {
+
+
+
+ {{@crate.name}}
+ {{#if @version}}
+ v{{@version.num}}
+
+ {{#if @version.yanked}}
+
+ {{svgJar 'trash'}}
+ Yanked
+
+
+ This crate has been yanked, but it is still available for download for other crates that may be
+ depending on it.
+
+
+ {{/if}}
+ {{/if}}
+
- {{@crate.name}}
- {{#if @version}}
- v{{@version.num}}
-
- {{#if @version.yanked}}
-
- {{svg-jar "trash"}}
- Yanked
-
-
- This crate has been yanked, but it is still available for download for other crates that
- may be depending on it.
-
-
- {{/if}}
- {{/if}}
-
-
- {{#if @crate.description}}
-
- {{@crate.description}}
-
- {{/if}}
-
- {{#if this.keywords}}
-
- {{#each this.keywords as |keyword|}}
-
-
- #{{keyword.id}}
-
-
- {{/each}}
-
- {{/if}}
-
- {{#if this.session.currentUser}}
-
- {{/if}}
-
-
-
-
- Readme
-
-
-
- {{pluralize @crate.num_versions "Version"}}
-
-
-
- Dependencies
-
-
-
- Dependents
-
-
- {{#if this.isOwner}}
-
- Settings
-
- {{/if}}
-
\ No newline at end of file
diff --git a/app/components/crate-header.js b/app/components/crate-header.js
deleted file mode 100644
index b5d76c9d1dc..00000000000
--- a/app/components/crate-header.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { service } from '@ember/service';
-import Component from '@glimmer/component';
-
-import { task } from 'ember-concurrency';
-import { alias } from 'macro-decorators';
-
-export default class CrateHeader extends Component {
- @service session;
-
- @alias('loadKeywordsTask.last.value') keywords;
-
- constructor() {
- super(...arguments);
-
- this.loadKeywordsTask.perform().catch(() => {
- // ignore all errors and just don't display keywords if the request fails
- });
- }
-
- get isOwner() {
- let userId = this.session.currentUser?.id;
- return this.args.crate?.hasOwnerUser(userId) ?? false;
- }
-
- loadKeywordsTask = task(async () => {
- return (await this.args.crate?.keywords) ?? [];
- });
-}
diff --git a/app/components/crate-list.gjs b/app/components/crate-list.gjs
new file mode 100644
index 00000000000..dfee19edbce
--- /dev/null
+++ b/app/components/crate-list.gjs
@@ -0,0 +1,13 @@
+import CrateRow from 'crates-io/components/crate-row';
+
+
+ {{! The extra div wrapper is needed for specificity issues with `margin` }}
+
+ {{#each @crates as |crate index|}}
+
- {{!-- The extra div wrapper is needed for specificity issues with `margin` --}}
-
- {{#each @crates as |crate index|}}
-
-
-
- {{/each}}
-
-
\ No newline at end of file
diff --git a/app/components/crate-row.gjs b/app/components/crate-row.gjs
new file mode 100644
index 00000000000..9547e0a2251
--- /dev/null
+++ b/app/components/crate-row.gjs
@@ -0,0 +1,88 @@
+import { on } from '@ember/modifier';
+
+import link_ from 'ember-link/helpers/link';
+import scopedClass from 'ember-scoped-css/helpers/scoped-class';
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+import and from 'ember-truth-helpers/helpers/and';
+import not from 'ember-truth-helpers/helpers/not';
+
+import CopyButton from 'crates-io/components/copy-button';
+import Tooltip from 'crates-io/components/tooltip';
+import dateFormatDistanceToNow from 'crates-io/helpers/date-format-distance-to-now';
+import dateFormatIso from 'crates-io/helpers/date-format-iso';
+import formatNum from 'crates-io/helpers/format-num';
+import truncateText from 'crates-io/helpers/truncate-text';
+
+
\ No newline at end of file
diff --git a/app/components/crate-sidebar.gjs b/app/components/crate-sidebar.gjs
new file mode 100644
index 00000000000..d5145eede4e
--- /dev/null
+++ b/app/components/crate-sidebar.gjs
@@ -0,0 +1,220 @@
+import { hash } from '@ember/helper';
+import { action } from '@ember/object';
+import { LinkTo } from '@ember/routing';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+
+import { didCancel } from 'ember-concurrency';
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+import eq from 'ember-truth-helpers/helpers/eq';
+import not from 'ember-truth-helpers/helpers/not';
+import or from 'ember-truth-helpers/helpers/or';
+
+import CopyButton from 'crates-io/components/copy-button';
+import InstallInstructions from 'crates-io/components/crate-sidebar/install-instructions';
+import Link from 'crates-io/components/crate-sidebar/link';
+import Edition from 'crates-io/components/edition';
+import LicenseExpression from 'crates-io/components/license-expression';
+import Msrv from 'crates-io/components/msrv';
+import OwnersList from 'crates-io/components/owners-list';
+import Tooltip from 'crates-io/components/tooltip';
+import dateFormat from 'crates-io/helpers/date-format';
+import dateFormatDistanceToNow from 'crates-io/helpers/date-format-distance-to-now';
+import dateFormatIso from 'crates-io/helpers/date-format-iso';
+import prettyBytes from 'crates-io/helpers/pretty-bytes';
+
+import { simplifyUrl } from './crate-sidebar/link';
+
+export default class CrateSidebar extends Component {
+
+
+
Sorry, there was a problem loading the graphing code.
-
-
- {{/if}}
-
\ No newline at end of file
diff --git a/app/components/dropdown.gjs b/app/components/dropdown.gjs
new file mode 100644
index 00000000000..84a8195a95e
--- /dev/null
+++ b/app/components/dropdown.gjs
@@ -0,0 +1,36 @@
+import { fn, hash } from '@ember/helper';
+import { action } from '@ember/object';
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+
+import onClickOutside from 'ember-click-outside/modifiers/on-click-outside';
+import onKey from 'ember-keyboard/modifiers/on-key';
+
+import DropdownContent from 'crates-io/components/dropdown/content';
+import DropdownMenu from 'crates-io/components/dropdown/menu';
+import DropdownTrigger from 'crates-io/components/dropdown/trigger';
+
+export default class Dropdown extends Component {
+
+
\ No newline at end of file
diff --git a/app/components/dropdown/menu-item.gjs b/app/components/dropdown/menu-item.gjs
new file mode 100644
index 00000000000..04dbbd48110
--- /dev/null
+++ b/app/components/dropdown/menu-item.gjs
@@ -0,0 +1,3 @@
+
+
-@Content>
\ No newline at end of file
diff --git a/app/components/dropdown/trigger.gjs b/app/components/dropdown/trigger.gjs
new file mode 100644
index 00000000000..51c267e463a
--- /dev/null
+++ b/app/components/dropdown/trigger.gjs
@@ -0,0 +1,9 @@
+import { on } from '@ember/modifier';
+
+
+
diff --git a/app/components/dropdown/trigger.hbs b/app/components/dropdown/trigger.hbs
deleted file mode 100644
index 9446793054e..00000000000
--- a/app/components/dropdown/trigger.hbs
+++ /dev/null
@@ -1,6 +0,0 @@
-
\ No newline at end of file
diff --git a/app/components/edition.gjs b/app/components/edition.gjs
new file mode 100644
index 00000000000..f58cba4f099
--- /dev/null
+++ b/app/components/edition.gjs
@@ -0,0 +1,19 @@
+import Tooltip from 'crates-io/components/tooltip';
+
+
+ {{@version.edition}}
+ edition
+
+
+ This crate version does not declare a Minimum Supported Rust Version, but does require the
+ {{@version.edition}}
+ Rust Edition.
+
+
+ {{@version.editionMsrv}}
+ was the first version of Rust in this edition, but this crate may require features that were added in later
+ versions of Rust.
+
+
+
+
diff --git a/app/components/edition.hbs b/app/components/edition.hbs
deleted file mode 100644
index 839bbac3bd3..00000000000
--- a/app/components/edition.hbs
+++ /dev/null
@@ -1,14 +0,0 @@
-
- {{@version.edition}} edition
-
-
- This crate version does not declare a Minimum Supported Rust Version, but
- does require the {{@version.edition}} Rust Edition.
-
-
- {{@version.editionMsrv}} was the first version of Rust in this edition,
- but this crate may require features that were added in later versions of
- Rust.
-
-
-
\ No newline at end of file
diff --git a/app/components/email-input.gjs b/app/components/email-input.gjs
new file mode 100644
index 00000000000..125316a2566
--- /dev/null
+++ b/app/components/email-input.gjs
@@ -0,0 +1,159 @@
+import { Input } from '@ember/component';
+import { fn } from '@ember/helper';
+import { on } from '@ember/modifier';
+import { action } from '@ember/object';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+
+import { task } from 'ember-concurrency';
+import perform from 'ember-concurrency/helpers/perform';
+import preventDefault from 'ember-event-helpers/helpers/prevent-default';
+import and from 'ember-truth-helpers/helpers/and';
+import not from 'ember-truth-helpers/helpers/not';
+
+export default class EmailInput extends Component {
+
+
+ {{#unless @user.email}}
+
+
+ Please add your email address. We will only use it to contact you about your account. We promise we'll never
+ share it!
+
\ No newline at end of file
diff --git a/app/components/header.gjs b/app/components/header.gjs
new file mode 100644
index 00000000000..e5c6a582707
--- /dev/null
+++ b/app/components/header.gjs
@@ -0,0 +1,177 @@
+import { hash } from '@ember/helper';
+import { on } from '@ember/modifier';
+import { action } from '@ember/object';
+import { LinkTo } from '@ember/routing';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+
+// Six hours.
+import perform from 'ember-concurrency/helpers/perform';
+import scopedClass from 'ember-scoped-css/helpers/scoped-class';
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+
+import ColorSchemeMenu from 'crates-io/components/color-scheme-menu';
+import Dropdown from 'crates-io/components/dropdown';
+import LoadingSpinner from 'crates-io/components/loading-spinner';
+import SearchForm from 'crates-io/components/search-form';
+import UserAvatar from 'crates-io/components/user-avatar';
+import dateFormat from 'crates-io/helpers/date-format';
+
+const SUDO_SESSION_DURATION_MS = 6 * 60 * 60 * 1000;
+
+export default class Header extends Component {
+
+
+
-{{/if}}
\ No newline at end of file
diff --git a/app/components/pending-owner-invite-row.js b/app/components/pending-owner-invite-row.js
deleted file mode 100644
index 3893ab2178f..00000000000
--- a/app/components/pending-owner-invite-row.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { service } from '@ember/service';
-import Component from '@glimmer/component';
-import { tracked } from '@glimmer/tracking';
-
-import { task } from 'ember-concurrency';
-
-export default class PendingOwnerInviteRow extends Component {
- @service notifications;
-
- @tracked isAccepted = false;
- @tracked isDeclined = false;
-
- acceptInvitationTask = task(async () => {
- this.args.invite.set('accepted', true);
-
- try {
- await this.args.invite.save();
- this.isAccepted = true;
- } catch (error) {
- let detail = error.errors?.[0]?.detail;
- if (detail && !detail.startsWith('{')) {
- this.notifications.error(`Error in accepting invite: ${detail}`);
- } else {
- this.notifications.error('Error in accepting invite');
- }
- }
- });
-
- declineInvitationTask = task(async () => {
- this.args.invite.set('accepted', false);
-
- try {
- await this.args.invite.save();
- this.isDeclined = true;
- } catch (error) {
- let detail = error.errors?.[0]?.detail;
- if (detail && !detail.startsWith('{')) {
- this.notifications.error(`Error in declining invite: ${detail}`);
- } else {
- this.notifications.error('Error in declining invite');
- }
- }
- });
-}
diff --git a/app/components/placeholder.gjs b/app/components/placeholder.gjs
new file mode 100644
index 00000000000..c6f791ed8bf
--- /dev/null
+++ b/app/components/placeholder.gjs
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/components/placeholder.hbs b/app/components/placeholder.hbs
deleted file mode 100644
index 041d8b1f3b6..00000000000
--- a/app/components/placeholder.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/app/components/privileged-action.js b/app/components/privileged-action.gjs
similarity index 70%
rename from app/components/privileged-action.js
rename to app/components/privileged-action.gjs
index 814de90ebc4..073da1ac295 100644
--- a/app/components/privileged-action.js
+++ b/app/components/privileged-action.gjs
@@ -29,7 +29,36 @@ import Component from '@glimmer/component';
* Note that all blocks will be output with a wrapping `
` for technical
* reasons, so be sure to style accordingly if necessary.
*/
+import Tooltip from 'crates-io/components/tooltip';
export default class PrivilegedAction extends Component {
+
+ {{#if this.isPrivileged}}
+
+ {{yield}}
+
+ {{else if this.canBePrivileged}}
+ {{#if (has-block 'placeholder')}}
+
+ {{yield to='placeholder'}}
+
+ {{else}}
+
+
+
+ You must enable admin actions before you can perform this operation.
+
+
\ No newline at end of file
diff --git a/app/components/settings/api-tokens.gjs b/app/components/settings/api-tokens.gjs
new file mode 100644
index 00000000000..c39dad71df4
--- /dev/null
+++ b/app/components/settings/api-tokens.gjs
@@ -0,0 +1,233 @@
+import { hash } from '@ember/helper';
+import { on } from '@ember/modifier';
+import { action } from '@ember/object';
+import { LinkTo } from '@ember/routing';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+
+import { task } from 'ember-concurrency';
+import perform from 'ember-concurrency/helpers/perform';
+import scopedClass from 'ember-scoped-css/helpers/scoped-class';
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+import eq from 'ember-truth-helpers/helpers/eq';
+import or from 'ember-truth-helpers/helpers/or';
+
+import CopyButton from 'crates-io/components/copy-button';
+import LoadingSpinner from 'crates-io/components/loading-spinner';
+import Tooltip from 'crates-io/components/tooltip';
+import dateFormatDistanceToNow from 'crates-io/helpers/date-format-distance-to-now';
+import isClipboardSupported from 'crates-io/helpers/is-clipboard-supported';
+
+import { patternDescription, scopeDescription } from '../../utils/token-scopes';
+
+export default class ApiTokens extends Component {
+
+
+
API Tokens
+
+
+ New Token
+
+
+
+
+
+ You can use the API tokens generated on this page to run
+ cargo
+ commands that need write access to crates.io. If you want to publish your own crates then this is required.
+
+
+
+ To prevent keys being silently leaked they are stored on crates.io in hashed form. This means you can only
+ download keys when you first create them. If you have old unused keys you can safely delete them and create a new
+ one.
+
+
+
+ To use an API token, run
+ cargo login
+ on the command line and paste the key when prompted. This will save it to a
+ local credentials file. For CI
+ systems you can use the
+ CARGO_REGISTRY_TOKEN
+ environment variable, but make sure that the token stays secret!
+
+ {{/if}}
+
+ @service store;
+ @service notifications;
+ @service router;
+
+ scopeDescription = scopeDescription;
+ patternDescription = patternDescription;
+
+ get sortedTokens() {
+ return this.args.tokens
+ .filter(t => !t.isNew)
+ .sort((a, b) => {
+ // Expired tokens are always shown after active ones.
+ if (a.isExpired && !b.isExpired) {
+ return 1;
+ } else if (b.isExpired && !a.isExpired) {
+ return -1;
+ }
+
+ // Otherwise, sort normally based on creation time.
+ return a.created_at < b.created_at ? 1 : -1;
+ });
+ }
+
+ listToParts(list) {
+ // We hardcode `en-US` here because the rest of the interface text is also currently displayed only in English.
+ return new Intl.ListFormat('en-US').formatToParts(list);
+ }
+
+ @action startNewToken() {
+ this.router.transitionTo('settings.tokens.new');
+ }
+
+ revokeTokenTask = task(async token => {
+ try {
+ await token.destroyRecord();
+
+ let index = this.args.tokens.indexOf(token);
+ if (index !== -1) {
+ this.args.tokens.splice(index, 1);
+ }
+ } catch (error) {
+ let detail = error.errors?.[0]?.detail;
+
+ let msg =
+ detail && !detail.startsWith('{')
+ ? `An error occurred while revoking this token, ${detail}`
+ : 'An unknown error occurred while revoking this token';
+
+ this.notifications.error(msg);
+ }
+ });
+}
diff --git a/app/components/settings/api-tokens.hbs b/app/components/settings/api-tokens.hbs
deleted file mode 100644
index 00e67ea503e..00000000000
--- a/app/components/settings/api-tokens.hbs
+++ /dev/null
@@ -1,155 +0,0 @@
-
-
API Tokens
-
-
- New Token
-
-
-
-
-
- You can use the API tokens generated on this page to run cargo
- commands that need write access to crates.io. If you want to publish your own
- crates then this is required.
-
-
-
- To prevent keys being silently leaked they are stored on crates.io in hashed form. This means you
- can only download keys when you first create them. If you have old unused keys you can safely delete
- them and create a new one.
-
-
-
- To use an API token, run cargo login
- on the command line and paste the key when prompted. This will save it to a
- local credentials file.
- For CI systems you can use the
- CARGO_REGISTRY_TOKEN
- environment variable, but make sure that the token stays secret!
-
\ No newline at end of file
diff --git a/app/components/side-menu/item.gjs b/app/components/side-menu/item.gjs
new file mode 100644
index 00000000000..f4fcbd8c248
--- /dev/null
+++ b/app/components/side-menu/item.gjs
@@ -0,0 +1,6 @@
+import { on } from '@ember/modifier';
+
+
-
-
-
-
diff --git a/app/templates/crate/delete.gjs b/app/templates/crate/delete.gjs
new file mode 100644
index 00000000000..2cca6f3b4c4
--- /dev/null
+++ b/app/templates/crate/delete.gjs
@@ -0,0 +1,96 @@
+import { Input } from '@ember/component';
+import { on } from '@ember/modifier';
+
+import perform from 'ember-concurrency/helpers/perform';
+import preventDefault from 'ember-event-helpers/helpers/prevent-default';
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+import not from 'ember-truth-helpers/helpers/not';
+import or from 'ember-truth-helpers/helpers/or';
+
+import LoadingSpinner from 'crates-io/components/loading-spinner';
+
+
\ No newline at end of file
diff --git a/app/templates/crate/docs.gjs b/app/templates/crate/docs.gjs
new file mode 100644
index 00000000000..6b60752a339
--- /dev/null
+++ b/app/templates/crate/docs.gjs
@@ -0,0 +1,10 @@
+
+
+
Documentation for {{@controller.model.name}}
+
+
+
+ Redirecting you to
+ {{@controller.model.documentation}}…
+
- The rebuild process may take several minutes to complete. You can monitor the build progress at the docs.rs build queue.
-
-
-
-
-
-
- Cancel
-
-
-
\ No newline at end of file
diff --git a/app/templates/crate/reverse-dependencies.gjs b/app/templates/crate/reverse-dependencies.gjs
new file mode 100644
index 00000000000..bfda7ad1775
--- /dev/null
+++ b/app/templates/crate/reverse-dependencies.gjs
@@ -0,0 +1,32 @@
+import CrateHeader from 'crates-io/components/crate-header';
+import Pagination from 'crates-io/components/pagination';
+import ResultsCount from 'crates-io/components/results-count';
+import RevDepRow from 'crates-io/components/rev-dep-row';
+
+
+
+ {{#if @controller.model}}
+
+
+
+
+
+ {{#each @controller.model as |dependency index|}}
+
+
+
+ {{/each}}
+
+
+
+ {{else}}
+
+ This crate is not used as a dependency in any other crate on crates.io.
+
- This crate is not used as a dependency in any other crate on crates.io.
-
-{{/if}}
\ No newline at end of file
diff --git a/app/templates/crate/settings/index.gjs b/app/templates/crate/settings/index.gjs
new file mode 100644
index 00000000000..13e61d2cafe
--- /dev/null
+++ b/app/templates/crate/settings/index.gjs
@@ -0,0 +1,170 @@
+import { Input } from '@ember/component';
+import { on } from '@ember/modifier';
+import { LinkTo } from '@ember/routing';
+
+import perform from 'ember-concurrency/helpers/perform';
+import preventDefault from 'ember-event-helpers/helpers/prevent-default';
+import pageTitle from 'ember-page-title/helpers/page-title';
+import not from 'ember-truth-helpers/helpers/not';
+
+import CrateHeader from 'crates-io/components/crate-header';
+import UserAvatar from 'crates-io/components/user-avatar';
+
+ {{pageTitle 'Manage Crate Settings'}}
+
+
+
+
\ No newline at end of file
diff --git a/app/templates/crate/versions.gjs b/app/templates/crate/versions.gjs
new file mode 100644
index 00000000000..712fbdc71f5
--- /dev/null
+++ b/app/templates/crate/versions.gjs
@@ -0,0 +1,71 @@
+import { hash } from '@ember/helper';
+import { on } from '@ember/modifier';
+
+import perform from 'ember-concurrency/helpers/perform';
+import and from 'ember-truth-helpers/helpers/and';
+import not from 'ember-truth-helpers/helpers/not';
+import or from 'ember-truth-helpers/helpers/or';
+
+import CrateHeader from 'crates-io/components/crate-header';
+import LoadingSpinner from 'crates-io/components/loading-spinner';
+import SortDropdown from 'crates-io/components/sort-dropdown';
+import Row from 'crates-io/components/version-list/row';
+import dateFormat from 'crates-io/helpers/date-format';
+
+
+
+
+
+ {{@controller.sortedVersions.length}}
+ of
+ {{@controller.crate.num_versions}}
+ {{@controller.crate.name}}
+ versions since
+ {{dateFormat @controller.crate.created_at 'PPP'}}
+
+
+
+ Sort by
+
+ Date
+ SemVer
+
+
+
+
+ {{#if @controller.sortedVersions}}
+
+ {{#each @controller.sortedVersions as |version|}}
+
diff --git a/app/templates/data-access.gjs b/app/templates/data-access.gjs
new file mode 100644
index 00000000000..e9adb4b6ea8
--- /dev/null
+++ b/app/templates/data-access.gjs
@@ -0,0 +1,113 @@
+import PageHeader from 'crates-io/components/page-header';
+import TextContent from 'crates-io/components/text-content';
+
+
+
+
+
+ crates.io provides several ways of accessing crate data and metadata, depending on what you specifically need.
+ Please try them in the order below.
+
+ The crates.io sparse index is available at
+ index.crates.io, which adheres to the
+ Cargo index format. The sparse index
+ provides an extremely efficient way of accessing metadata on a single or small number of crates.
+
+
+
+ Each index file provides newline delimited JSON metadata on all published versions of the crate, organised into
+ index files. For example,
+ information on the
+ base64
+ crate can be found at
+ https://index.crates.io/ba/se/base64.
+
+
+
+ No rate limits are required to use data from the sparse crate index.
+
+ Older versions of Cargo use the crate index provided in the
+ rust-lang/crates.io-index
+ repository on GitHub. This remains available for use, and may be a more efficient way of accessing crate
+ metadata for projects that require most or all crates to be included than the sparse index.
+
+ crates.io provides an API that is a superset of the functionality required by the
+ Cargo Web API. Should you be unable
+ to use one of the previous options, you are welcome to use the crates.io API provided you abide by the following
+ limits:
+
+
+
+
A maximum of 1 request per second, and
+
+ A
+ user-agent
+ header that identifies your application. We strongly suggest providing a way for us to contact you (whether
+ through a repository, or an e-mail address, or whatever is appropriate) so that we can reach out to work with
+ you should there be issues.
+
+ If none of the above options suit your needs, please contact the crates.io team either at
+ help@crates.io, or by starting
+ a discussion on GitHub, and we'll be happy to
+ discuss solutions that might exist outside of the above guidelines.
+
- crates.io provides several ways of accessing crate data and metadata,
- depending on what you specifically need. Please try them in the order below.
-
- The crates.io sparse index is available at
- index.crates.io, which adheres to the
- Cargo index format.
- The sparse index provides an extremely efficient way of accessing metadata on
- a single or small number of crates.
-
-
-
- Each index file provides newline delimited JSON metadata on all published
- versions of the crate, organised into
- index files.
- For example, information on the base64 crate can be found at
- https://index.crates.io/ba/se/base64.
-
-
-
- No rate limits are required to use data from the sparse crate index.
-
- Older versions of Cargo use the crate index provided in the
- rust-lang/crates.io-index repository on GitHub.
- This remains available for use, and may be a more efficient way of accessing
- crate metadata for projects that require most or all crates to be included
- than the sparse index.
-
- crates.io provides an API that is a superset of the functionality required by
- the
- Cargo Web API.
- Should you be unable to use one of the previous options, you are welcome to
- use the crates.io API provided you abide by the following limits:
-
-
-
-
A maximum of 1 request per second, and
-
- A user-agent header that identifies your application. We
- strongly suggest providing a way for us to contact you (whether through a
- repository, or an e-mail address, or whatever is appropriate) so that we can
- reach out to work with you should there be issues.
-
- If none of the above options suit your needs, please contact the crates.io
- team either at help@crates.io, or by
- starting
- a discussion on GitHub,
- and we'll be happy to discuss solutions that might exist outside of the above
- guidelines.
-
-
\ No newline at end of file
diff --git a/app/templates/docs/trusted-publishing.gjs b/app/templates/docs/trusted-publishing.gjs
new file mode 100644
index 00000000000..802580b934b
--- /dev/null
+++ b/app/templates/docs/trusted-publishing.gjs
@@ -0,0 +1,128 @@
+import PageHeader from 'crates-io/components/page-header';
+import TextContent from 'crates-io/components/text-content';
+import highlightSyntax from 'crates-io/modifiers/highlight-syntax';
+
+
+
+
+
What is Trusted Publishing?
+
+ Trusted Publishing is a secure way to publish your Rust crates from GitHub Actions without manually managing API
+ tokens. It uses OpenID Connect (OIDC) to verify that your workflow is running from your repository, then provides
+ a short-lived token for publishing.
+
+
+
+ Instead of storing long-lived API tokens in your repository secrets, Trusted Publishing allows GitHub Actions to
+ authenticate directly with crates.io using cryptographically signed tokens that prove the workflow's identity.
+
+
+
+ Note:
+ crates.io currently only supports GitHub Actions, but we are planning to support other CI/CD platforms like GitLab
+ CI/CD in the future.
+
+
+
Security Benefits
+
+
No long-lived API tokens to manage or rotate
+
Tokens automatically expire after 30 minutes
+
Repository and workflow verification prevents unauthorized publishing
+
OIDC-based cryptographic verification with GitHub's public JWKS
+
Optional GitHub Actions environments for additional access controls
+
+
+
Quick Start
+
Follow these steps to set up Trusted Publishing for your crate:
+
+
+
Configure your crate for Trusted Publishing in the crates.io settings
+
Set up your GitHub Actions workflow
+ with the required permissions and authentication action
+
Publish your crate using the automated workflow
+
+
+
Prerequisites
+
+
Your crate must already be published to crates.io (initial publish requires an API token)
+
You must be an owner of the crate on crates.io
+
Your repository must be on GitHub
+
+
+
Configuring Trusted Publishing
+
+ Configure your crate on crates.io:
+
+
+
+
Go to your crate's Settings → Trusted Publishing
+
Click the "Add" button and fill in:
+
+
Repository owner: Your GitHub username or organization
+
Repository name: The name of your repository
+
Workflow filename:
+ The filename of your GitHub Actions workflow (e.g., "release.yml")
+
Environment: Optional environment name if you're using GitHub environments
+
+
+
Save the configuration
+
+
+
GitHub Actions Setup
+
+ Create a workflow file at
+ .github/workflows/release.yml. This example workflow will automatically publish your crate each time
+ you push a version tag (like
+ v1.0.0):
+
name: Publish to crates.io on: push: tags: ['v*'] # Triggers
+ when pushing tags starting with 'v' jobs: publish: runs-on: ubuntu-latest environment: release # Optional: for
+ enhanced security permissions: id-token: write # Required for OIDC token exchange steps: - uses:
+ actions/checkout@v4 - uses: rust-lang/crates-io-auth-action@v1 id: auth - run: cargo publish env:
+ CARGO_REGISTRY_TOKEN: $\{\{ steps.auth.outputs.token \}\}
+
+
+ Optional:
+ For enhanced security, create a GitHub Actions environment named "release" in your repository settings with
+ protection rules like required reviewers or deployment branches.
+
+
+
Security & Best Practices
+
+
Use specific workflow filenames to reduce the attack surface
+
Use GitHub Actions environments with protection rules for sensitive publishing
+
Limit workflow triggers to specific tags or protected branches
+
Review all actions used in your release workflow
+
Monitor publishing activities through crates.io email notifications
+
+
+
+ How it works:
+ GitHub Actions generates an OIDC token that proves your workflow's identity. The
+ rust-lang/crates-io-auth-action
+ exchanges this for a 30-minute access token that
+ cargo publish
+ uses automatically.
+
+
+
Migration from API Tokens
+
+ To migrate from API tokens: set up Trusted Publishing following the steps above, test it, then remove the API
+ token from your repository secrets. Both methods can be used simultaneously during transition.
+
- Trusted Publishing is a secure way to publish your Rust crates from GitHub Actions without manually managing API tokens.
- It uses OpenID Connect (OIDC) to verify that your workflow is running from your repository, then provides a short-lived token for publishing.
-
-
-
- Instead of storing long-lived API tokens in your repository secrets, Trusted Publishing allows GitHub Actions to authenticate
- directly with crates.io using cryptographically signed tokens that prove the workflow's identity.
-
-
-
- Note: crates.io currently only supports GitHub Actions, but we are planning to support other
- CI/CD platforms like GitLab CI/CD in the future.
-
-
-
Security Benefits
-
-
No long-lived API tokens to manage or rotate
-
Tokens automatically expire after 30 minutes
-
Repository and workflow verification prevents unauthorized publishing
-
OIDC-based cryptographic verification with GitHub's public JWKS
-
Optional GitHub Actions environments for additional access controls
-
-
-
Quick Start
-
Follow these steps to set up Trusted Publishing for your crate:
-
-
-
Configure your crate for Trusted Publishing in the crates.io settings
-
Set up your GitHub Actions workflow with the required permissions and authentication action
-
Publish your crate using the automated workflow
-
-
-
Prerequisites
-
-
Your crate must already be published to crates.io (initial publish requires an API token)
-
You must be an owner of the crate on crates.io
-
Your repository must be on GitHub
-
-
-
Configuring Trusted Publishing
-
- Configure your crate on crates.io:
-
-
-
-
Go to your crate's Settings → Trusted Publishing
-
Click the "Add" button and fill in:
-
-
Repository owner: Your GitHub username or organization
-
Repository name: The name of your repository
-
Workflow filename: The filename of your GitHub Actions workflow (e.g., "release.yml")
-
Environment: Optional environment name if you're using GitHub environments
-
-
-
Save the configuration
-
-
-
GitHub Actions Setup
-
- Create a workflow file at .github/workflows/release.yml. This example workflow will automatically publish your crate each time you push a version tag (like v1.0.0):
-
- Optional: For enhanced security, create a GitHub Actions environment named "release"
- in your repository settings with protection rules like required reviewers or deployment branches.
-
-
-
Security & Best Practices
-
-
Use specific workflow filenames to reduce the attack surface
-
Use GitHub Actions environments with protection rules for sensitive publishing
-
Limit workflow triggers to specific tags or protected branches
-
Review all actions used in your release workflow
-
Monitor publishing activities through crates.io email notifications
-
-
-
- How it works: GitHub Actions generates an OIDC token that proves your workflow's identity.
- The rust-lang/crates-io-auth-action exchanges this for a 30-minute access token that
- cargo publish uses automatically.
-
-
-
Migration from API Tokens
-
- To migrate from API tokens: set up Trusted Publishing following the steps above, test it,
- then remove the API token from your repository secrets. Both methods can be used simultaneously during transition.
-
-
\ No newline at end of file
diff --git a/app/templates/error.gjs b/app/templates/error.gjs
new file mode 100644
index 00000000000..f21b4c56275
--- /dev/null
+++ b/app/templates/error.gjs
@@ -0,0 +1,7 @@
+
+
+ Instantly publish your crates and install them. Use the API to interact and find out more information about
+ available crates. Become a contributor and enhance the site with your work.
+
+ Unfortunately something went wrong while loading the crates.io summary data. Feel free to try again, or let the
+ crates.io team
+ know if the problem persists.
+
- Instantly publish your crates and install them. Use the API to
- interact and find out more information about available crates. Become
- a contributor and enhance the site with your work.
-
-
-
-
-
-
-
-
-{{#if this.dataTask.lastComplete.error}}
-
- Unfortunately something went wrong while loading the crates.io summary data.
- Feel free to try again, or let the crates.io
- team know if the problem persists.
-
- {{/each}}
- {{else}}
- {{#each this.model.popular_categories as |category|}}
-
-
-
- {{/each}}
- {{/if}}
-
-
-
-{{/if}}
\ No newline at end of file
diff --git a/app/templates/install.gjs b/app/templates/install.gjs
new file mode 100644
index 00000000000..241c2759fba
--- /dev/null
+++ b/app/templates/install.gjs
@@ -0,0 +1,9 @@
+import PageHeader from 'crates-io/components/page-header';
+
+
+
+
+ Redirecting you to
+ https://doc.rust-lang.org/cargo/getting-started/installation.html…
+
diff --git a/app/templates/policies/index.gjs b/app/templates/policies/index.gjs
new file mode 100644
index 00000000000..12271d2028a
--- /dev/null
+++ b/app/templates/policies/index.gjs
@@ -0,0 +1,165 @@
+import { LinkTo } from '@ember/routing';
+
+import PageHeader from 'crates-io/components/page-header';
+import TextContent from 'crates-io/components/text-content';
+
+
+
+
+
Short version:
+ crates.io is a critical resource for the Rust ecosystem, which hosts a variety of packages from a diverse
+ group of users. That resource is only effective when our users are able to work together as part of a community
+ in good faith. While using crates.io, you must comply with our Acceptable Use Policies, which include some
+ restrictions on content and conduct on crates.io related to user safety, intellectual property, privacy,
+ authenticity, and other limitations. In short, be excellent to each other!
+
+
We do not allow content or activity on crates.io that:
is unlawful or promotes unlawful activities, incurring legal liability in the countries the Rust Foundation
+ officially operates in
+
is libelous, defamatory, or fraudulent
+
amounts to phishing or attempted phishing
+
infringes any proprietary right of any party, including patent, trademark, trade secret, copyright, right of
+ publicity, or other right
+
unlawfully shares unauthorized product licensing keys, software for generating unauthorized product licensing
+ keys, or software for bypassing checks for product licensing keys, including extension of a free license beyond
+ its trial period
+
contains malicious code, such as computer viruses, computer worms, rootkits, back doors, or spyware, including
+ content submitted for research purposes (tools designed and documented explicitly to assist in security research
+ are acceptable, but exploits and malware that use the crates.io registry as a deployment or delivery vector are
+ not)
+
uses obfuscation to hide or mask functionality
+
is discriminatory toward, harasses or abuses another individual or group
+
threatens or incites violence toward any individual or group, especially on the basis of who they are
+
is using crates.io as a platform for propagating abuse on other platforms
+
violates the privacy of any third party, such as by posting another person's personal information without
+ consent
+
gratuitously depicts or glorifies violence, including violent images
+
is sexually obscene or relates to sexual exploitation or abuse, including of minors (see "Sexually
+ Obscene Content" section below)
+
is off-topic, or interacts with platform features in a way that significantly or repeatedly disrupts the
+ experience of other users
+
exists only to reserve a name for a prolonged period of time (often called "name squatting") without
+ having any genuine functionality, purpose, or significant development activity on the corresponding repository
+
is related to buying, selling, or otherwise trading of package names or any other names on crates.io for money
+ or other compensation
+
impersonates any person or entity, including through false association with crates.io, or by fraudulently
+ misrepresenting your identity or site's purpose
+
is related to inauthentic interactions, such as fake accounts and automated inauthentic activity
+
is using our servers for any form of excessive automated bulk activity, to place undue burden on our servers
+ through automated means, or to relay any form of unsolicited advertising or solicitation through our servers,
+ such as get-rich-quick schemes
+
+ is using our servers for other automated excessive bulk activity or coordinated inauthentic activity, such as:
+
+
spamming
+
cryptocurrency mining
+
+
+
is not functionally compatible with the cargo build tool (for example, a "package" cannot simply be
+ a PNG or JPEG image, a movie file, or a text document uploaded directly to the registry)
+
is abusing the package index for purposes it was not intended
+
+
+
You are responsible for using crates.io in compliance with all applicable laws, regulations, and all of our
+ policies. These policies may be updated from time to time. We will interpret our policies and resolve disputes in
+ favor of protecting users as a whole. The crates.io team reserves the possibility to evaluate each instance on a
+ case-by-case basis.
+
+
For issues such as DMCA violations, or trademark and copyright infringements, the crates.io team will respect the
+ legal decisions of the
+ Rust Foundation
+ as the official legal entity providing the crates.io service.
+
+
Package Ownership
+
+
crates.io has a first-come, first-serve policy on crate names. Upon publishing a package, the publisher will be
+ made owner of the package on crates.io.
+
+
If you want to take over a package, we recommend you try and contact the current owner directly. If the current
+ owner agrees, they can add you as an owner of the crate, and you can then remove them, if necessary. For security
+ reasons, the crates.io team will not transfer ownership of existing crates without the explicit approval of the
+ current owner.
+
+
If you are the author of a crate that another person wants to take over: keep in mind that the new owner might
+ develop your crate in a way you never intended it, or might completely repurpose your crate. Transferring a crate
+ to a malicious user could have a significant impact for any existing users of your crate.
+
+
Crate owners can delete their crates under certain conditions: the crate has been published for less than 72
+ hours, or the crate only has a single owner, the crate has been downloaded less than 500 times for each month it
+ has been published, and the crate is not depended upon by any other crate on crates.io. If these conditions are
+ not met, the crate will not be deleted. In exceptional cases crate owners may contact
+ the crates.io team
+ to request deletion of a crate that does not meet these conditions.
+
+
The crates.io team may delete crates from the registry that do not comply with the policies on this document. In
+ larger cases of squatting attacks this may happen without prior notification to the author, but in most cases the
+ team will first give the author the chance to justify the purpose of the crate.
+
+
Data Access
+
+
Details on how to access the crates.io data can be found on the dedicated
+ Data Access Policy
+ page.
+
+
Security
+
+
Please see the Security page.
+
+
Sexually Obscene Content
+
+
We do not tolerate content associated with sexual exploitation or abuse of another individual, including where
+ minors are concerned. We do not allow sexually themed or suggestive content that serves little or no purpose other
+ than to solicit an erotic or shocking response, particularly where that content is amplified by its placement in
+ profiles or other social contexts.
+
+
This includes:
+
+
+
Pornographic content
+
Non-consensual intimate imagery
+
Graphic depictions of sexual acts including photographs, video, animation, drawings, computer-generated
+ images, or text-based content
+
+
+
+
+
We recognize that not all nudity or content related to sexuality is obscene. We may allow visual and/or textual
+ depictions in artistic, educational, historical or journalistic contexts, or as it relates to victim advocacy. In
+ some cases a disclaimer can help communicate the context of the project.
+
+
Violations and Enforcement
+
+
crates.io retains full discretion to take action in response to a violation of these policies, including account
+ suspension, account termination, or removal of content.
+
+
We will however not be proactively monitoring the site for these kinds of violations, but instead relying on the
+ community to draw them to our attention.
+
+
While the majority of interactions between individuals in the Rust community falls within our policies,
+ violations of those policies do occur at times. When they do, the crates.io team may need to take enforcement
+ action to address the violations. In all cases, content and account deletion is permanent and there is no basis to
+ reverse these moderation actions taken by the crates.io team. Account suspension may be lifted at the team's
+ discretion however, for example in the case of someone's account being compromised.
+
+
Reporting
+
+
Please report violations of this policy to help@crates.io.
Short version:
- crates.io is a critical resource for the Rust ecosystem, which hosts a variety of packages from a diverse group of
- users. That resource is only effective when our users are able to work together as part of a community in good
- faith. While using crates.io, you must comply with our Acceptable Use Policies, which include some restrictions on
- content and conduct on crates.io related to user safety, intellectual property, privacy, authenticity, and other
- limitations. In short, be excellent to each other!
-
-
We do not allow content or activity on crates.io that:
is unlawful or promotes unlawful activities, incurring legal liability in the countries the Rust Foundation
- officially operates in
-
is libelous, defamatory, or fraudulent
-
amounts to phishing or attempted phishing
-
infringes any proprietary right of any party, including patent, trademark, trade secret, copyright, right of
- publicity, or other right
-
unlawfully shares unauthorized product licensing keys, software for generating unauthorized product licensing
- keys, or software for bypassing checks for product licensing keys, including extension of a free license beyond its
- trial period
-
contains malicious code, such as computer viruses, computer worms, rootkits, back doors, or spyware, including
- content submitted for research purposes (tools designed and documented explicitly to assist in security research are
- acceptable, but exploits and malware that use the crates.io registry as a deployment or delivery vector are not)
-
uses obfuscation to hide or mask functionality
-
is discriminatory toward, harasses or abuses another individual or group
-
threatens or incites violence toward any individual or group, especially on the basis of who they are
-
is using crates.io as a platform for propagating abuse on other platforms
-
violates the privacy of any third party, such as by posting another person's personal information without
- consent
-
gratuitously depicts or glorifies violence, including violent images
-
is sexually obscene or relates to sexual exploitation or abuse, including of minors (see "Sexually Obscene
- Content" section below)
-
is off-topic, or interacts with platform features in a way that significantly or repeatedly disrupts the
- experience of other users
-
exists only to reserve a name for a prolonged period of time (often called "name squatting") without
- having any genuine functionality, purpose, or significant development activity on the corresponding repository
-
is related to buying, selling, or otherwise trading of package names or any other names on crates.io for money or
- other compensation
-
impersonates any person or entity, including through false association with crates.io, or by fraudulently
- misrepresenting your identity or site's purpose
-
is related to inauthentic interactions, such as fake accounts and automated inauthentic activity
-
is using our servers for any form of excessive automated bulk activity, to place undue burden on our servers
- through automated means, or to relay any form of unsolicited advertising or solicitation through our servers, such
- as get-rich-quick schemes
-
- is using our servers for other automated excessive bulk activity or coordinated inauthentic activity, such as:
-
-
spamming
-
cryptocurrency mining
-
-
-
is not functionally compatible with the cargo build tool (for example, a "package" cannot simply be a
- PNG or JPEG image, a movie file, or a text document uploaded directly to the registry)
-
is abusing the package index for purposes it was not intended
-
-
-
You are responsible for using crates.io in compliance with all applicable laws, regulations, and all of our policies.
- These policies may be updated from time to time. We will interpret our policies and resolve disputes in favor of
- protecting users as a whole. The crates.io team reserves the possibility to evaluate each instance on a case-by-case
- basis.
-
-
For issues such as DMCA violations, or trademark and copyright infringements, the crates.io team will respect the
- legal decisions of the Rust Foundation as the official legal entity
- providing the crates.io service.
-
-
Package Ownership
-
-
crates.io has a first-come, first-serve policy on crate names. Upon publishing a package, the publisher will be made
- owner of the package on crates.io.
-
-
If you want to take over a package, we recommend you try and contact the current owner directly. If the
- current owner agrees, they can add you as an owner of the crate, and you can then remove them, if necessary.
- For security reasons, the crates.io team will not transfer ownership of existing crates without the explicit
- approval of the current owner.
-
-
If you are the author of a crate that another person wants to take over: keep in mind that the new owner might
- develop your crate in a way you never intended it, or might completely repurpose your crate. Transferring a crate
- to a malicious user could have a significant impact for any existing users of your crate.
-
-
Crate owners can delete their crates under certain conditions: the crate has been published for less than 72 hours, or
- the crate only has a single owner, the crate has been downloaded less than 500 times for each month it has been
- published, and the crate is not depended upon by any other crate on crates.io. If these conditions are not met, the
- crate will not be deleted. In exceptional cases crate owners may contact the crates.io
- team to request deletion of a crate that does not meet these conditions.
-
-
The crates.io team may delete crates from the registry that do not comply with the policies on this document. In
- larger cases of squatting attacks this may happen without prior notification to the author, but in most cases the team
- will first give the author the chance to justify the purpose of the crate.
-
-
Data Access
-
-
Details on how to access the crates.io data can be found on the dedicated Data Access
- Policy page.
-
-
Security
-
-
Please see the Security page.
-
-
Sexually Obscene Content
-
-
We do not tolerate content associated with sexual exploitation or abuse of another individual, including where minors
- are concerned. We do not allow sexually themed or suggestive content that serves little or no purpose other than to
- solicit an erotic or shocking response, particularly where that content is amplified by its placement in profiles or
- other social contexts.
-
-
This includes:
-
-
-
Pornographic content
-
Non-consensual intimate imagery
-
Graphic depictions of sexual acts including photographs, video, animation, drawings, computer-generated images, or
- text-based content
-
-
-
-
-
We recognize that not all nudity or content related to sexuality is obscene. We may allow visual and/or textual
- depictions in artistic, educational, historical or journalistic contexts, or as it relates to victim advocacy. In some
- cases a disclaimer can help communicate the context of the project.
-
-
Violations and Enforcement
-
-
crates.io retains full discretion to take action in response to a violation of these policies, including account
- suspension, account termination, or removal of content.
-
-
We will however not be proactively monitoring the site for these kinds of violations, but instead relying on the
- community to draw them to our attention.
-
-
While the majority of interactions between individuals in the Rust community falls within our policies, violations of
- those policies do occur at times. When they do, the crates.io team may need to take enforcement action to address the
- violations. In all cases, content and account deletion is permanent and there is no basis to reverse these moderation
- actions taken by the crates.io team. Account suspension may be lifted at the team's discretion however, for
- example in the case of someone's account being compromised.
-
-
Reporting
-
-
Please report violations of this policy to help@crates.io.
-
\ No newline at end of file
diff --git a/app/templates/policies/security.gjs b/app/templates/policies/security.gjs
new file mode 100644
index 00000000000..82a75dda8f1
--- /dev/null
+++ b/app/templates/policies/security.gjs
@@ -0,0 +1,70 @@
+import { LinkTo } from '@ember/routing';
+
+import PageHeader from 'crates-io/components/page-header';
+import TextContent from 'crates-io/components/text-content';
+
+
+
+
+
+
Security of crates.io itself
+
+
Safety is one of the core principles of Rust, and to that end, we would like to ensure that cargo, crates.io,
+ docs.rs, and related tools have secure implementations. To disclose security vulnerabilities in the crates.io
+ service itself (as opposed to crates hosted on crates.io) or any other
+ repository in the rust-lang organization, please follow the
+ Rust Security policy.
+
+
Thank you for taking the time to responsibly disclose any issues you find.
+
+
Security of crates hosted on crates.io
+
+
To disclose security vulnerabilities found in a crate that is hosted on crates.io, seek guidance from the
+ individual crate's owners and their specific policies. Commonly, projects include a file named
+ SECURITY.md
+ that contains the crate's security policies and procedures.
+
+
Intentionally malicious code is against
+ crates.io's usage policies; please report crates violating these policies to
+ help@crates.io.
+
+
Rustsec Security Advisory Database for receiving security updates
Security is a value important to the Rust ecosystem as a whole, not just to the Rust language. If you are a crate
+ author and you have received a high impact/severity security bug report for your crate, the Rust Foundation and
+ the Rust Project are available to help manage the situation. The Rust Project or the Rust Foundation may also be
+ the ones reaching out to you, if they have been informed of a security issue.
Employs security engineers who can help assessing the problem, developing mitigations, and estimating impact.
+
Has a network of member organizations that can help with testing resources and also employ security experts
+ who can help with assessing and fixing issues.
+
Employs communications staff who can manage publishing notifications and fielding inquiries.
+
Has contacts with government agencies tasked with cybersecurity protections who may have information on
+ exploitation or impact of a security problem.
+
+
+
The Rust Project can coordinate actions among other parts of the ecosystem that may need to be updated to address
+ a fix.
+
+
Please reach out to
+ contact@rustfoundation.org
+ if either the Rust Project or the Rust Foundation can help you by providing security support in the areas listed
+ above or in another way! These are just a few examples of the kind of help available to crate authors facing
+ security challenges.
Safety is one of the core principles of Rust, and to that end, we would like to ensure that cargo, crates.io, docs.rs, and
- related tools have secure implementations. To disclose security vulnerabilities in the crates.io service itself (as opposed
- to crates hosted on crates.io) or any other repository in the rust-lang
- organization, please follow the Rust Security policy.
-
-
Thank you for taking the time to responsibly disclose any issues you find.
-
-
Security of crates hosted on crates.io
-
-
To disclose security vulnerabilities found in a crate that is hosted on crates.io, seek guidance from the individual crate's
- owners and their specific policies. Commonly, projects include a file named SECURITY.md that contains the
- crate's security policies and procedures.
-
-
Intentionally malicious code is against crates.io's usage policies; please report crates
- violating these policies to help@crates.io.
-
-
Rustsec Security Advisory Database for receiving security updates
Security is a value important to the Rust ecosystem as a whole, not just to the Rust language. If you are a crate author and
- you have received a high impact/severity security bug report for your crate, the Rust Foundation and the Rust Project are
- available to help manage the situation. The Rust Project or the Rust Foundation may also be the ones reaching out to you, if
- they have been informed of a security issue.
Employs security engineers who can help assessing the problem, developing mitigations, and estimating impact.
-
Has a network of member organizations that can help with testing resources and also employ security experts who can help
- with assessing and fixing issues.
-
Employs communications staff who can manage publishing notifications and fielding inquiries.
-
Has contacts with government agencies tasked with cybersecurity protections who may have information on exploitation or
- impact of a security problem.
-
-
-
The Rust Project can coordinate actions among other parts of the ecosystem that may need to be updated to address a fix.
-
-
Please reach out to contact@rustfoundation.org if either the Rust Project or
- the Rust Foundation can help you by providing security support in the areas listed above or in another way! These are just a
- few examples of the kind of help available to crate authors facing security challenges.
-
-
diff --git a/app/templates/search.gjs b/app/templates/search.gjs
new file mode 100644
index 00000000000..300386e37e5
--- /dev/null
+++ b/app/templates/search.gjs
@@ -0,0 +1,76 @@
+import { concat, hash } from '@ember/helper';
+import { on } from '@ember/modifier';
+
+import pageTitle from 'ember-page-title/helpers/page-title';
+
+import CrateList from 'crates-io/components/crate-list';
+import PageHeader from 'crates-io/components/page-header';
+import Pagination from 'crates-io/components/pagination';
+import ResultsCount from 'crates-io/components/results-count';
+import SortDropdown from 'crates-io/components/sort-dropdown';
+
+ {{pageTitle @controller.pageTitle}}
+
+
+
+ {{#if @controller.hasMultiCategoryFilter}}
+
+ Support for using multiple
+ category:
+ filters is not yet implemented.
+
+ {{else if @controller.dataTask.lastComplete.error}}
+
+ Unfortunately something went wrong while loading the search results. Feel free to try again, or let the
+ crates.io team
+ know if the problem persists.
+
- Support for using multiple category: filters is not yet implemented.
-
-{{/if}}
-
-{{#if this.firstResultPending}}
-
Loading search results...
-{{else if this.dataTask.lastComplete.error}}
-
- Unfortunately something went wrong while loading the search results. Feel
- free to try again, or let the crates.io
- team know if the problem persists.
-
-{{/if}}
diff --git a/app/templates/settings/email-notifications.gjs b/app/templates/settings/email-notifications.gjs
new file mode 100644
index 00000000000..a25cf5d0348
--- /dev/null
+++ b/app/templates/settings/email-notifications.gjs
@@ -0,0 +1,71 @@
+import { on } from '@ember/modifier';
+
+import preventDefault from 'ember-event-helpers/helpers/prevent-default';
+import pageTitle from 'ember-page-title/helpers/page-title';
+
+import OwnedCrateRow from 'crates-io/components/owned-crate-row';
+import PageHeader from 'crates-io/components/page-header';
+import SettingsPage from 'crates-io/components/settings-page';
+
+
+ {{pageTitle 'Settings'}}
+
+
+
+
+
+
+
diff --git a/app/templates/settings/email-notifications.hbs b/app/templates/settings/email-notifications.hbs
deleted file mode 100644
index ea17092b3b9..00000000000
--- a/app/templates/settings/email-notifications.hbs
+++ /dev/null
@@ -1,52 +0,0 @@
-{{page-title 'Settings'}}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/templates/settings/profile.gjs b/app/templates/settings/profile.gjs
new file mode 100644
index 00000000000..1d26409a77e
--- /dev/null
+++ b/app/templates/settings/profile.gjs
@@ -0,0 +1,80 @@
+import { Input } from '@ember/component';
+import { on } from '@ember/modifier';
+
+import perform from 'ember-concurrency/helpers/perform';
+import pageTitle from 'ember-page-title/helpers/page-title';
+
+import EmailInput from 'crates-io/components/email-input';
+import LoadingSpinner from 'crates-io/components/loading-spinner';
+import PageHeader from 'crates-io/components/page-header';
+import SettingsPage from 'crates-io/components/settings-page';
+import UserAvatar from 'crates-io/components/user-avatar';
+import UserLink from 'crates-io/components/user-link';
+
+
+ {{pageTitle 'Settings'}}
+
+
+
+
+
+
Profile Information
+
+
+
+
+
+
+
+
Name
+
{{@controller.model.user.name}}
+
GitHub Account
+
{{@controller.model.user.login}}
+
+
+
+
+ To update your name and GitHub account, change them in your GitHub profile, then sign out and login again to
+ crates.io. You cannot change these settings directly on crates.io, but we accept whatever values come from
+ GitHub.
+
- To update your name and GitHub account, change them in your GitHub profile, then sign out and login again to
- crates.io.
- You cannot change these settings directly on crates.io, but we accept whatever values come from GitHub.
-
-
- {{/if}}
-
\ No newline at end of file
diff --git a/app/templates/team.gjs b/app/templates/team.gjs
new file mode 100644
index 00000000000..e31a97ecba3
--- /dev/null
+++ b/app/templates/team.gjs
@@ -0,0 +1,53 @@
+import { hash } from '@ember/helper';
+
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+
+import CrateList from 'crates-io/components/crate-list';
+import PageHeader from 'crates-io/components/page-header';
+import Pagination from 'crates-io/components/pagination';
+import ResultsCount from 'crates-io/components/results-count';
+import SortDropdown from 'crates-io/components/sort-dropdown';
+import UserAvatar from 'crates-io/components/user-avatar';
+import UserLink from 'crates-io/components/user-link';
+
+
+
+
+
-
-
-
-
\ No newline at end of file
diff --git a/app/templates/user.gjs b/app/templates/user.gjs
new file mode 100644
index 00000000000..7811b1d3668
--- /dev/null
+++ b/app/templates/user.gjs
@@ -0,0 +1,46 @@
+import { hash } from '@ember/helper';
+
+import svgJar from 'ember-svg-jar/helpers/svg-jar';
+
+import CrateList from 'crates-io/components/crate-list';
+import PageHeader from 'crates-io/components/page-header';
+import Pagination from 'crates-io/components/pagination';
+import ResultsCount from 'crates-io/components/results-count';
+import SortDropdown from 'crates-io/components/sort-dropdown';
+import UserAvatar from 'crates-io/components/user-avatar';
+import UserLink from 'crates-io/components/user-link';
+
+
+
+
+