snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
This commit is contained in:
27
packages/common/native/Cargo.toml
Normal file
27
packages/common/native/Cargo.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
license-file = "LICENSE"
|
||||
name = "affine_common"
|
||||
publish = false
|
||||
version = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
hashcash = ["chrono", "hex", "sha3", "rand"]
|
||||
napi = ["dep:napi"]
|
||||
|
||||
[dependencies]
|
||||
chrono = { workspace = true, optional = true }
|
||||
hex = { workspace = true, optional = true }
|
||||
napi = { workspace = true, optional = true }
|
||||
rand = { workspace = true, optional = true }
|
||||
sha3 = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
tempfile = "3"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "hashcash"
|
||||
44
packages/common/native/LICENSE
Normal file
44
packages/common/native/LICENSE
Normal file
@@ -0,0 +1,44 @@
|
||||
The AFFiNE Enterprise Edition (EE) license (the “EE License”)
|
||||
Copyright (c) 2022-present TOEVERYTHING PTE. LTD. and its affiliates.
|
||||
|
||||
With regard to the AFFiNE Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the AFFiNE Subscription Terms of Service, available
|
||||
at https://affine.pro/terms/#subscription (the “EE Terms”), or other
|
||||
agreement governing the use of the Software, as agreed by you and AFFiNE,
|
||||
and otherwise have a valid AFFiNE Enterprise Edition subscription for the
|
||||
correct number of user seats. Subject to the foregoing sentence, you are free to
|
||||
modify this Software and publish patches to the Software. You agree that AFFiNE
|
||||
and/or its licensors (as applicable) retain all right, title and interest in and
|
||||
to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid AFFiNE Enterprise Edition subscription for the correct
|
||||
number of user seats. Notwithstanding the foregoing, you may copy and modify
|
||||
the Software for development and testing purposes, without requiring a
|
||||
subscription. You agree that AFFiNE and/or its licensors (as applicable) retain
|
||||
all right, title and interest in and to all such modifications. You are not
|
||||
granted any other rights beyond what is expressly stated herein. Subject to the
|
||||
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
This EE License applies only to the part of this Software that is not
|
||||
distributed as part of AFFiNE Community Edition (CE). Any part of this Software
|
||||
distributed as part of AFFiNE CE or is served client-side as an image, font,
|
||||
cascading stylesheet (CSS), file which produces or is compiled, arranged,
|
||||
augmented, or combined into client-side JavaScript, in whole or in part, is
|
||||
copyrighted under the MPL2.0 license. The full text of this EE License shall
|
||||
be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the AFFiNE Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
27
packages/common/native/benches/hashcash.rs
Normal file
27
packages/common/native/benches/hashcash.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use std::hint::black_box;
|
||||
|
||||
use affine_common::hashcash::Stamp;
|
||||
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
|
||||
|
||||
fn bench_hashcash(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("hashcash");
|
||||
|
||||
group.bench_function(BenchmarkId::from_parameter("Generate"), |b| {
|
||||
b.iter(|| {
|
||||
black_box(Stamp::mint("test".to_string(), Some(20)).format());
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_function(BenchmarkId::from_parameter("Verify"), |b| {
|
||||
b.iter(|| {
|
||||
black_box(
|
||||
Stamp::try_from("1:20:20241114061212:test::RsRAAkoxjr4FattQ:292f0d")
|
||||
.unwrap()
|
||||
.check(20, "test"),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_hashcash);
|
||||
criterion_main!(benches);
|
||||
182
packages/common/native/fixtures/demo.docx.0.md
Normal file
182
packages/common/native/fixtures/demo.docx.0.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# DOCX Demo
|
||||
|
||||
# <a name="OLE_LINK1"></a><a name="OLE_LINK2"></a><a name="_Toc359077851"></a>Demonstration of DOCX support in calibre
|
||||
|
||||
This document demonstrates the ability of the calibre DOCX Input plugin to convert the various typographic features in a Microsoft Word (2007 and newer) document. Convert this document to a modern ebook format, such as AZW3 for Kindles or EPUB for other ebook readers, to see it in action.
|
||||
|
||||
There is support for images, tables, lists, footnotes, endnotes, links, dropcaps and various types of text and paragraph level formatting.
|
||||
|
||||
To see the DOCX conversion in action, simply add this file to calibre using the **“Add Books” **button and then click “**Convert”. ** Set the output format in the top right corner of the conversion dialog to EPUB or AZW3 and click **“OK”**.
|
||||
|
||||
# <a name="_Toc359077852"></a>Text Formatting
|
||||
|
||||
## <a name="_Toc359077853"></a>Inline formatting
|
||||
|
||||
Here, we demonstrate various types of inline text formatting and the use of embedded fonts.
|
||||
|
||||
Here is some **bold, ***italic, ****bold-italic, ***__underlined __and ~~struck out ~~ text. Then, we have a superscript and a subscript. Now we see some red, green and blue text. Some text with a yellow highlight. Some text in a box. Some text in inverse video.
|
||||
|
||||
A paragraph with styled text: subtle emphasis followed by strong text and intense emphasis. This paragraph uses document wide styles for styling rather than inline text properties as demonstrated in the previous paragraph — calibre can handle both with equal ease.
|
||||
|
||||
## <a name="_Toc359077854"></a>Fun with fonts
|
||||
|
||||
This document has embedded the Ubuntu font family. The body text is in the Ubuntu typeface, here is some text in the Ubuntu Mono typeface, notice how every letter has the same width, even i and m. Every embedded font will automatically be embedded in the output ebook during conversion.
|
||||
|
||||
## ***<a name="_Paragraph_level_formatting"></a>******<a name="_Toc359077855"></a>******Paragraph level formatting***
|
||||
|
||||
You can do crazy things with paragraphs, if the urge strikes you. For instance this paragraph is right aligned and has a right border. It has also been given a light gray background.
|
||||
|
||||
For the lovers of poetry amongst you, paragraphs with hanging indents, like this often come in handy. You can use hanging indents to ensure that a line of poetry retains its individual identity as a line even when the screen is too narrow to display it as a single line. Not only does this paragraph have a hanging indent, it is also has an extra top margin, setting it apart from the preceding paragraph.
|
||||
|
||||
# <a name="_Toc359077856"></a>Tables
|
||||
|
||||
| | |
|
||||
| ----------- | -------- |
|
||||
| ITEM | NEEDED |
|
||||
| Books | 1 |
|
||||
| Pens | 3 |
|
||||
| Pencils | 2 |
|
||||
| Highlighter | 2 colors |
|
||||
| Scissors | 1 pair |
|
||||
|
||||
Tables in Word can vary from the extremely simple to the extremely complex. calibre tries to do its best when converting tables. While you may run into trouble with the occasional table, the vast majority of common cases should be converted very well, as demonstrated in this section. Note that for optimum results, when creating tables in Word, you should set their widths using percentages, rather than absolute units. To the left of this paragraph is a floating two column table with a nice green border and header row.
|
||||
|
||||
Now let’s look at a fancier table—one with alternating row colors and partial borders. This table is stretched out to take 100% of the available width.
|
||||
|
||||
| | | | | | |
|
||||
| ------------ | ------- | ------- | ------- | ------- | ------- |
|
||||
| City or Town | Point A | Point B | Point C | Point D | Point E |
|
||||
| Point A | — | | | | |
|
||||
| Point B | 87 | — | | | |
|
||||
| Point C | 64 | 56 | — | | |
|
||||
| Point D | 37 | 32 | 91 | — | |
|
||||
| Point E | 93 | 35 | 54 | 43 | — |
|
||||
|
||||
Next, we see a table with special formatting in various locations. Notice how the formatting for the header row and sub header rows is preserved.
|
||||
|
||||
| | | | |
|
||||
| ---------------- | ------------- | ------------------- | ------ |
|
||||
| College | New students | Graduating students | Change |
|
||||
| | Undergraduate | | |
|
||||
| Cedar University | 110 | 103 | +7 |
|
||||
| Oak Institute | 202 | 210 | -8 |
|
||||
| | Graduate | | |
|
||||
| Cedar University | 24 | 20 | +4 |
|
||||
| Elm College | 43 | 53 | -10 |
|
||||
| Total | 998 | 908 | 90 |
|
||||
|
||||
Source: Fictitious data, for illustration purposes only
|
||||
|
||||
Next, we have something a little more complex, a nested table, i.e. a table inside another table. Additionally, the inner table has some of its cells merged. The table is displayed horizontally centered.
|
||||
|
||||
| | |
|
||||
| --- | -------------------------------------------------------------- |
|
||||
| | To the left is a table inside a table, with some cells merged. |
|
||||
|
||||
We end with a fancy calendar, note how much of the original formatting is preserved. Note that this table will only display correctly on relatively wide screens. In general, very wide tables or tables whose cells have fixed width requirements don’t fare well in ebooks.
|
||||
|
||||
| | | | | | | | | | | | | |
|
||||
| ------------- | | --- | | --- | | --- | | --- | | --- | | --- |
|
||||
| December 2007 | | | | | | | | | | | | |
|
||||
| Sun | | Mon | | Tue | | Wed | | Thu | | Fri | | Sat |
|
||||
| | | | | | | | | | | | | 1 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 9 | | 10 | | 11 | | 12 | | 13 | | 14 | | 15 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 16 | | 17 | | 18 | | 19 | | 20 | | 21 | | 22 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 23 | | 24 | | 25 | | 26 | | 27 | | 28 | | 29 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 30 | | 31 | | | | | | | | | | |
|
||||
|
||||
# <a name="_Toc359077857"></a>Structural Elements
|
||||
|
||||
Miscellaneous structural elements you can add to your document, like footnotes, endnotes, dropcaps and the like.
|
||||
|
||||
## <a name="_Toc359077858"></a>Footnotes & Endnotes
|
||||
|
||||
Footnotes and endnotes are automatically recognized and both are converted to endnotes, with backlinks for maximum ease of use in ebook devices.
|
||||
|
||||
## <a name="_Toc359077859"></a>Dropcaps
|
||||
|
||||
D
|
||||
|
||||
rop caps are used to emphasize the leading paragraph at the start of a section. In Word it is possible to specify how many lines of text a drop-cap should use. Because of limitations in ebook technology, this is not possible when converting. Instead, the converted drop cap will use font size and line height to simulate the effect as well as possible. While not as good as the original, the result is usually tolerable. This paragraph has a “D” dropcap set to occupy three lines of text with a font size of 58.5 pts. Depending on the screen width and capabilities of the device you view the book on, this dropcap can look anything from perfect to ugly.
|
||||
|
||||
## <a name="_Toc359077860"></a>Links
|
||||
|
||||
Two kinds of links are possible, those that refer to an external website and those that refer to locations inside the document itself. Both are supported by calibre. For example, here is a link pointing to the [calibre download page](http://calibre-ebook.com/download). Then we have a link that points back to the section on [paragraph level formatting](#_Paragraph_level_formatting) in this document.
|
||||
|
||||
## <a name="_Toc359077861"></a>Table of Contents
|
||||
|
||||
There are two approaches that calibre takes when generating a Table of Contents. The first is if the Word document has a Table of Contents itself. Provided that the Table of Contents uses hyperlinks, calibre will automatically use it. The levels of the Table of Contents are identified by their left indent, so if you want the ebook to have a multi-level Table of Contents, make sure you create a properly indented Table of Contents in Word.
|
||||
|
||||
If no Table of Contents is found in the document, then a table of contents is automatically generated from the headings in the document. A heading is identified as something that has the Heading 1 or Heading 2, etc. style applied to it. These headings are turned into a Table of Contents with Heading 1 being the topmost level, Heading 2 the second level and so on.
|
||||
|
||||
You can see the Table of Contents created by calibre by clicking the Table of Contents button in whatever viewer you are using to view the converted ebook.
|
||||
|
||||
# <a name="_Toc359077862"></a>Images
|
||||
|
||||
Images can be of three main types. Inline images are images that are part of the normal text flow, like this image of a green dot . Inline images do not cause breaks in the text and are usually small in size. The next category of image is a floating image, one that “floats “ on the page and is surrounded by text. Word supports more types of floating images than are possible with current ebook technology, so the conversion maps floating images to simple left and right floats, as you can see with the left and right arrow images on the sides of this paragraph.
|
||||
|
||||
The final type of image is a “block” image, one that becomes a paragraph on its own and has no text on either side. Below is a centered green dot.
|
||||
|
||||
Centered images like this are useful for large pictures that should be a focus of attention.
|
||||
|
||||
Generally, it is not possible to translate the exact positioning of images from a Word document to an ebook. That is because in Word, image positioning is specified in absolute units from the page boundaries. There is no analogous technology in ebooks, so the conversion will usually end up placing the image either centered or floating close to the point in the text where it was inserted, not necessarily where it appears on the page in Word.
|
||||
|
||||
# <a name="_Toc359077863"></a>Lists
|
||||
|
||||
All types of lists are supported by the conversion, with the exception of lists that use fancy bullets, these get converted to regular bullets.
|
||||
|
||||
## <a name="_Toc359077864"></a>Bulleted List
|
||||
|
||||
- One
|
||||
|
||||
- Two
|
||||
|
||||
## <a name="_Toc359077865"></a>Numbered List
|
||||
|
||||
1. One, with a very long line to demonstrate that the hanging indent for the list is working correctly
|
||||
|
||||
2. Two
|
||||
|
||||
## <a name="_Toc359077866"></a>Multi-level Lists
|
||||
|
||||
1. One
|
||||
|
||||
2. Two
|
||||
|
||||
3. Three
|
||||
|
||||
4. Four with a very long line to demonstrate that the hanging indent for the list is working correctly.
|
||||
|
||||
5. Five
|
||||
|
||||
6. Six
|
||||
|
||||
A Multi-level list with bullets:
|
||||
|
||||
- One
|
||||
|
||||
- Two
|
||||
|
||||
- This bullet uses an image as the bullet item
|
||||
|
||||
- Four
|
||||
|
||||
- Five
|
||||
|
||||
## <a name="_Toc359077867"></a>Continued Lists
|
||||
|
||||
i. One
|
||||
|
||||
j. Two
|
||||
|
||||
An interruption in our regularly scheduled listing, for this essential and very relevant public service announcement.
|
||||
|
||||
k. We now resume our normal programming
|
||||
|
||||
l. Four
|
||||
182
packages/common/native/fixtures/demo.docx.md
Normal file
182
packages/common/native/fixtures/demo.docx.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# DOCX Demo
|
||||
|
||||
# <a name="OLE_LINK1"></a><a name="OLE_LINK2"></a><a name="_Toc359077851"></a>Demonstration of DOCX support in calibre
|
||||
|
||||
This document demonstrates the ability of the calibre DOCX Input plugin to convert the various typographic features in a Microsoft Word (2007 and newer) document. Convert this document to a modern ebook format, such as AZW3 for Kindles or EPUB for other ebook readers, to see it in action.
|
||||
|
||||
There is support for images, tables, lists, footnotes, endnotes, links, dropcaps and various types of text and paragraph level formatting.
|
||||
|
||||
To see the DOCX conversion in action, simply add this file to calibre using the **“Add Books” **button and then click “**Convert”. ** Set the output format in the top right corner of the conversion dialog to EPUB or AZW3 and click **“OK”**.
|
||||
|
||||
# <a name="_Toc359077852"></a>Text Formatting
|
||||
|
||||
## <a name="_Toc359077853"></a>Inline formatting
|
||||
|
||||
Here, we demonstrate various types of inline text formatting and the use of embedded fonts.
|
||||
|
||||
Here is some **bold, ***italic, ****bold-italic, ***__underlined __and ~~struck out ~~ text. Then, we have a superscript and a subscript. Now we see some red, green and blue text. Some text with a yellow highlight. Some text in a box. Some text in inverse video.
|
||||
|
||||
A paragraph with styled text: subtle emphasis followed by strong text and intense emphasis. This paragraph uses document wide styles for styling rather than inline text properties as demonstrated in the previous paragraph — calibre can handle both with equal ease.
|
||||
|
||||
## <a name="_Toc359077854"></a>Fun with fonts
|
||||
|
||||
This document has embedded the Ubuntu font family. The body text is in the Ubuntu typeface, here is some text in the Ubuntu Mono typeface, notice how every letter has the same width, even i and m. Every embedded font will automatically be embedded in the output ebook during conversion.
|
||||
|
||||
## ***<a name="_Paragraph_level_formatting"></a>******<a name="_Toc359077855"></a>******Paragraph level formatting***
|
||||
|
||||
You can do crazy things with paragraphs, if the urge strikes you. For instance this paragraph is right aligned and has a right border. It has also been given a light gray background.
|
||||
|
||||
For the lovers of poetry amongst you, paragraphs with hanging indents, like this often come in handy. You can use hanging indents to ensure that a line of poetry retains its individual identity as a line even when the screen is too narrow to display it as a single line. Not only does this paragraph have a hanging indent, it is also has an extra top margin, setting it apart from the preceding paragraph.
|
||||
|
||||
# <a name="_Toc359077856"></a>Tables
|
||||
|
||||
| | |
|
||||
| ----------- | -------- |
|
||||
| ITEM | NEEDED |
|
||||
| Books | 1 |
|
||||
| Pens | 3 |
|
||||
| Pencils | 2 |
|
||||
| Highlighter | 2 colors |
|
||||
| Scissors | 1 pair |
|
||||
|
||||
Tables in Word can vary from the extremely simple to the extremely complex. calibre tries to do its best when converting tables. While you may run into trouble with the occasional table, the vast majority of common cases should be converted very well, as demonstrated in this section. Note that for optimum results, when creating tables in Word, you should set their widths using percentages, rather than absolute units. To the left of this paragraph is a floating two column table with a nice green border and header row.
|
||||
|
||||
Now let’s look at a fancier table—one with alternating row colors and partial borders. This table is stretched out to take 100% of the available width.
|
||||
|
||||
| | | | | | |
|
||||
| ------------ | ------- | ------- | ------- | ------- | ------- |
|
||||
| City or Town | Point A | Point B | Point C | Point D | Point E |
|
||||
| Point A | — | | | | |
|
||||
| Point B | 87 | — | | | |
|
||||
| Point C | 64 | 56 | — | | |
|
||||
| Point D | 37 | 32 | 91 | — | |
|
||||
| Point E | 93 | 35 | 54 | 43 | — |
|
||||
|
||||
Next, we see a table with special formatting in various locations. Notice how the formatting for the header row and sub header rows is preserved.
|
||||
|
||||
| | | | |
|
||||
| ---------------- | ------------- | ------------------- | ------ |
|
||||
| College | New students | Graduating students | Change |
|
||||
| | Undergraduate | | |
|
||||
| Cedar University | 110 | 103 | +7 |
|
||||
| Oak Institute | 202 | 210 | -8 |
|
||||
| | Graduate | | |
|
||||
| Cedar University | 24 | 20 | +4 |
|
||||
| Elm College | 43 | 53 | -10 |
|
||||
| Total | 998 | 908 | 90 |
|
||||
|
||||
Source: Fictitious data, for illustration purposes only
|
||||
|
||||
Next, we have something a little more complex, a nested table, i.e. a table inside another table. Additionally, the inner table has some of its cells merged. The table is displayed horizontally centered.
|
||||
|
||||
| | |
|
||||
| --- | -------------------------------------------------------------- |
|
||||
| | To the left is a table inside a table, with some cells merged. |
|
||||
|
||||
We end with a fancy calendar, note how much of the original formatting is preserved. Note that this table will only display correctly on relatively wide screens. In general, very wide tables or tables whose cells have fixed width requirements don’t fare well in ebooks.
|
||||
|
||||
| | | | | | | | | | | | | |
|
||||
| ------------- | | --- | | --- | | --- | | --- | | --- | | --- |
|
||||
| December 2007 | | | | | | | | | | | | |
|
||||
| Sun | | Mon | | Tue | | Wed | | Thu | | Fri | | Sat |
|
||||
| | | | | | | | | | | | | 1 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 9 | | 10 | | 11 | | 12 | | 13 | | 14 | | 15 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 16 | | 17 | | 18 | | 19 | | 20 | | 21 | | 22 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 23 | | 24 | | 25 | | 26 | | 27 | | 28 | | 29 |
|
||||
| | | | | | | | | | | | | |
|
||||
| 30 | | 31 | | | | | | | | | | |
|
||||
|
||||
# <a name="_Toc359077857"></a>Structural Elements
|
||||
|
||||
Miscellaneous structural elements you can add to your document, like footnotes, endnotes, dropcaps and the like.
|
||||
|
||||
## <a name="_Toc359077858"></a>Footnotes & Endnotes
|
||||
|
||||
Footnotes and endnotes are automatically recognized and both are converted to endnotes, with backlinks for maximum ease of use in ebook devices.
|
||||
|
||||
## <a name="_Toc359077859"></a>Dropcaps
|
||||
|
||||
D
|
||||
|
||||
rop caps are used to emphasize the leading paragraph at the start of a section. In Word it is possible to specify how many lines of text a drop-cap should use. Because of limitations in ebook technology, this is not possible when converting. Instead, the converted drop cap will use font size and line height to simulate the effect as well as possible. While not as good as the original, the result is usually tolerable. This paragraph has a “D” dropcap set to occupy three lines of text with a font size of 58.5 pts. Depending on the screen width and capabilities of the device you view the book on, this dropcap can look anything from perfect to ugly.
|
||||
|
||||
## <a name="_Toc359077860"></a>Links
|
||||
|
||||
Two kinds of links are possible, those that refer to an external website and those that refer to locations inside the document itself. Both are supported by calibre. For example, here is a link pointing to the [calibre download page](http://calibre-ebook.com/download). Then we have a link that points back to the section on [paragraph level formatting](#_Paragraph_level_formatting) in this document.
|
||||
|
||||
## <a name="_Toc359077861"></a>Table of Contents
|
||||
|
||||
There are two approaches that calibre takes when generating a Table of Contents. The first is if the Word document has a Table of Contents itself. Provided that the Table of Contents uses hyperlinks, calibre will automatically use it. The levels of the Table of Contents are identified by their left indent, so if you want the ebook to have a multi-level Table of Contents, make sure you create a properly indented Table of Contents in Word.
|
||||
|
||||
If no Table of Contents is found in the document, then a table of contents is automatically generated from the headings in the document. A heading is identified as something that has the Heading 1 or Heading 2, etc. style applied to it. These headings are turned into a Table of Contents with Heading 1 being the topmost level, Heading 2 the second level and so on.
|
||||
|
||||
You can see the Table of Contents created by calibre by clicking the Table of Contents button in whatever viewer you are using to view the converted ebook.
|
||||
|
||||
# <a name="_Toc359077862"></a>Images
|
||||
|
||||
Images can be of three main types. Inline images are images that are part of the normal text flow, like this image of a green dot . Inline images do not cause breaks in the text and are usually small in size. The next category of image is a floating image, one that “floats “ on the page and is surrounded by text. Word supports more types of floating images than are possible with current ebook technology, so the conversion maps floating images to simple left and right floats, as you can see with the left and right arrow images on the sides of this paragraph.
|
||||
|
||||
The final type of image is a “block” image, one that becomes a paragraph on its own and has no text on either side. Below is a centered green dot.
|
||||
|
||||
Centered images like this are useful for large pictures that should be a focus of attention.
|
||||
|
||||
Generally, it is not possible to translate the exact positioning of images from a Word document to an ebook. That is because in Word, image positioning is specified in absolute units from the page boundaries. There is no analogous technology in ebooks, so the conversion will usually end up placing the image either centered or floating close to the point in the text where it was inserted, not necessarily where it appears on the page in Word.
|
||||
|
||||
# <a name="_Toc359077863"></a>Lists
|
||||
|
||||
All types of lists are supported by the conversion, with the exception of lists that use fancy bullets, these get converted to regular bullets.
|
||||
|
||||
## <a name="_Toc359077864"></a>Bulleted List
|
||||
|
||||
- One
|
||||
|
||||
- Two
|
||||
|
||||
## <a name="_Toc359077865"></a>Numbered List
|
||||
|
||||
1. One, with a very long line to demonstrate that the hanging indent for the list is working correctly
|
||||
|
||||
2. Two
|
||||
|
||||
## <a name="_Toc359077866"></a>Multi-level Lists
|
||||
|
||||
1. One
|
||||
|
||||
2. Two
|
||||
|
||||
3. Three
|
||||
|
||||
4. Four with a very long line to demonstrate that the hanging indent for the list is working correctly.
|
||||
|
||||
5. Five
|
||||
|
||||
6. Six
|
||||
|
||||
A Multi-level list with bullets:
|
||||
|
||||
- One
|
||||
|
||||
- Two
|
||||
|
||||
- This bullet uses an image as the bullet item
|
||||
|
||||
- Four
|
||||
|
||||
- Five
|
||||
|
||||
## <a name="_Toc359077867"></a>Continued Lists
|
||||
|
||||
i. One
|
||||
|
||||
j. Two
|
||||
|
||||
An interruption in our regularly scheduled listing, for this essential and very relevant public service announcement.
|
||||
|
||||
k. We now resume our normal programming
|
||||
|
||||
l. Four
|
||||
BIN
packages/common/native/fixtures/demo.ydoc
Normal file
BIN
packages/common/native/fixtures/demo.ydoc
Normal file
Binary file not shown.
567
packages/common/native/fixtures/demo.ydoc.json
Normal file
567
packages/common/native/fixtures/demo.ydoc.json
Normal file
@@ -0,0 +1,567 @@
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"block_id": "F_zl1z0ex6dSxM25ZBUWk",
|
||||
"flavour": "affine:page",
|
||||
"content": [
|
||||
"Write, Draw, Plan all at Once."
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": null,
|
||||
"parent_block_id": null,
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "U8g2Edcy8rSmu_XUpYSTz",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. "
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "NxvF6M1Zo-TrUoJyFbMy4",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "VHVvola5BtXnC7FMaGzE7",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"You own your data, with no compromises"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "Hvbw1lSZ7Bl-LMiOc_xFb",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Local-first & Real-time collaborative"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "2N8pJ32byPEc7dlJv-0cC",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"We love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience."
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "rysuvULJQgFPRmNB_iTk3",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time."
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "zbvmiGhuxn0_tfJ_e4N2V",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "omG6fe87r60dPxCtv_Odb",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"omG6fe87r60dPxCtv_Odb\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "CQeQaaREQwGDXg9oAng4q",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Blocks that assemble your next docs, tasks kanban or whiteboard"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "QqLfbOIINoAxapnB23E5t",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"QqLfbOIINoAxapnB23E5t\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "RTtZAHZG4xoAXKKnEsRhB",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"There is a large overlap of their atomic \"building blocks\" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. "
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "Fpxp7rZCad7-W51xCWta1",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"Fpxp7rZCad7-W51xCWta1\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "c_KFpzTBHdioeoIsnLIjd",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"We are building AFFiNE to be a fundamental open source platform that contains all the building blocks for docs, task management and visual collaboration, hoping you can shape your next workflow with us that can make your life better and also connect others, too."
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "Fpxp7rZCad7-W51xCWta1",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"Fpxp7rZCad7-W51xCWta1\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "O6D7PxXwCbfCLp1_peft1",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"If you want to learn more about the product design of AFFiNE, here goes the concepts:"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "Fpxp7rZCad7-W51xCWta1",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"Fpxp7rZCad7-W51xCWta1\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "os84XIVFN6z6aN9tq16S5",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"To Shape, not to adapt. AFFiNE is built for individuals & teams who care about their data, who refuse vendor lock-in, and who want to have control over their essential tools."
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "Fpxp7rZCad7-W51xCWta1",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"Fpxp7rZCad7-W51xCWta1\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "8jk1eREgtKdhwtee0nym-",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"A true canvas for blocks in any form"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "kDyc-RntYCDWSSYFl4SSn",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Many editor apps claimed to be a canvas for productivity. Since the Mother of All Demos, Douglas Engelbart, a creative and programable digital workspace has been a pursuit and an ultimate mission for generations of tool makers. "
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "k0e4IqfQ2PRmsXjzDQ-3T",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "QR-4T-qYH3gTbbo_VKjU-",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"\"We shape our tools and thereafter our tools shape us”. A lot of pioneers have inspired us a long the way, e.g.:"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "nyEEsW01cCQVIr7yG9ywg",
|
||||
"flavour": "affine:list",
|
||||
"content": [
|
||||
"Quip & Notion with their great concept of \"everything is a block\""
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "ZmeTH3oq8ON10pqV1pQ-n",
|
||||
"flavour": "affine:list",
|
||||
"content": [
|
||||
"Trello with their Kanban"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "SbbdUF95MVoBTlxILHyUL",
|
||||
"flavour": "affine:list",
|
||||
"content": [
|
||||
"Airtable & Miro with their no-code programable datasheets"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "fIQp-yM2v8Iar7kXAooXh",
|
||||
"flavour": "affine:list",
|
||||
"content": [
|
||||
"Miro & Whimiscal with their edgeless visual whiteboard"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "2S9xQwALMBxbas1N6Eyf4",
|
||||
"flavour": "affine:list",
|
||||
"content": [
|
||||
"Remnote & Capacities with their object-based tag system"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "sfycWDfMpgKsE7s5qucWr",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"sfycWDfMpgKsE7s5qucWr\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "C5xu77eIYukdKCu7h0Cjp",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"For more details, please refer to our RoadMap"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "tPAicJ4WMxtBhys0Exlxq",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"tPAicJ4WMxtBhys0Exlxq\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "2goqe7zWXhtKX-pLcYN-h",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Self Host"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "tPAicJ4WMxtBhys0Exlxq",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"tPAicJ4WMxtBhys0Exlxq\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "cBud4or0twRvF36twhwqZ",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Self host AFFiNE"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "tPAicJ4WMxtBhys0Exlxq",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"tPAicJ4WMxtBhys0Exlxq\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"flavour": "affine:database",
|
||||
"content": [
|
||||
"Learning From",
|
||||
"Title",
|
||||
"Tag",
|
||||
"Reference",
|
||||
"Developers",
|
||||
"AFFiNE"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "j9pzdPaGIVH627CPh_mik",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "YJ13TsE8mv5mxy2DIpMOD",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Affine Development"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "T_BOz9f-9uD5QjKABiciE",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"For developers or installations guides, please go to AFFiNE Doc"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "yiMJW4ASGVUC7mly7ulce",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Quip & Notion with their great concept of \"everything is a block\""
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "qug1UtELLsBg2XwU1IJYK",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Trello with their Kanban"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "p86Sceg7KYFe1OgUUswCM",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Airtable & Miro with their no-code programable datasheets"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "ahyiL8RAajMoIoDekk2Je",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Miro & Whimiscal with their edgeless visual whiteboard"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "pKh_LNdwWD-yLDh-TVYAz",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Remnote & Capacities with their object-based tag system"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:database",
|
||||
"parent_block_id": "FB07QqbHZhRqj43IEOzJP",
|
||||
"additional": "{\"databaseName\":\"Learning From\",\"displayMode\":\"page\",\"noteBlockId\":\"j9pzdPaGIVH627CPh_mik\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "b0ftuFAo7qDYRiI18TN6b",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"Affine Development"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "wyVFKrydUAthKQEML84vE",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"wyVFKrydUAthKQEML84vE\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "64rS_MtVI-f_MpE6qCbls",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
"For developer or installation guides, please go to AFFiNE Development"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "wyVFKrydUAthKQEML84vE",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"wyVFKrydUAthKQEML84vE\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "7dotDICZwPWNvFXZSh-oF",
|
||||
"flavour": "affine:paragraph",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:note",
|
||||
"parent_block_id": "wyVFKrydUAthKQEML84vE",
|
||||
"additional": "{\"displayMode\":\"page\",\"noteBlockId\":\"wyVFKrydUAthKQEML84vE\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "Jn4N8YdsFnqjBn-ae5zeR",
|
||||
"flavour": "affine:surface",
|
||||
"content": [
|
||||
"",
|
||||
" ",
|
||||
"AFFiNE ",
|
||||
"Database Reference",
|
||||
"Development",
|
||||
"Related Articles",
|
||||
"Self-host",
|
||||
"What is AFFiNE",
|
||||
"You can check these URLs to learn about AFFiNE"
|
||||
],
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:page",
|
||||
"parent_block_id": "F_zl1z0ex6dSxM25ZBUWk",
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "YkZXI2iWRvQARfQPqspP_",
|
||||
"flavour": "affine:bookmark",
|
||||
"content": null,
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:surface",
|
||||
"parent_block_id": "Jn4N8YdsFnqjBn-ae5zeR",
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "6xwR75KDkxvygEFWZfmhZ",
|
||||
"flavour": "affine:bookmark",
|
||||
"content": null,
|
||||
"blob": null,
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:surface",
|
||||
"parent_block_id": "Jn4N8YdsFnqjBn-ae5zeR",
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "AjY4OYuyp2536pBZlf-vD",
|
||||
"flavour": "affine:image",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": [
|
||||
"BFZk3c2ERp-sliRvA7MQ_p3NdkdCLt2Ze0DQ9i21dpA="
|
||||
],
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:surface",
|
||||
"parent_block_id": "Jn4N8YdsFnqjBn-ae5zeR",
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "ErTXTP8VqP5fabuB5FZHH",
|
||||
"flavour": "affine:image",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": [
|
||||
"HWvCItS78DzPGbwcuaGcfkpVDUvL98IvH5SIK8-AcL8="
|
||||
],
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:surface",
|
||||
"parent_block_id": "Jn4N8YdsFnqjBn-ae5zeR",
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
},
|
||||
{
|
||||
"block_id": "hMg8RXNlkD7XJS9b27fGA",
|
||||
"flavour": "affine:image",
|
||||
"content": [
|
||||
""
|
||||
],
|
||||
"blob": [
|
||||
"ZRKpsBoC88qEMmeiXKXqywfA1rLvWoLa5rpEh9x9Oj0="
|
||||
],
|
||||
"ref_doc_id": null,
|
||||
"ref_info": null,
|
||||
"parent_flavour": "affine:surface",
|
||||
"parent_block_id": "Jn4N8YdsFnqjBn-ae5zeR",
|
||||
"additional": "{\"displayMode\":\"edgeless\"}"
|
||||
}
|
||||
],
|
||||
"title": "Write, Draw, Plan all at Once.",
|
||||
"summary": "AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. You own your data, with no compromisesLocal-first & Real-time collaborativeWe love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.Blocks that assemble your next docs, tasks kanban or whiteboardThere is a large overlap of their atomic \"building blocks\" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. "
|
||||
}
|
||||
7
packages/common/native/fixtures/sample.c
Normal file
7
packages/common/native/fixtures/sample.c
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello, World!\n");
|
||||
return 0;
|
||||
}
|
||||
1
packages/common/native/fixtures/sample.c.0.md
Normal file
1
packages/common/native/fixtures/sample.c.0.md
Normal file
@@ -0,0 +1 @@
|
||||
#include <stdio.h>
|
||||
4
packages/common/native/fixtures/sample.c.1.md
Normal file
4
packages/common/native/fixtures/sample.c.1.md
Normal file
@@ -0,0 +1,4 @@
|
||||
int main() {
|
||||
printf("Hello, World!\n");
|
||||
return 0;
|
||||
}
|
||||
481
packages/common/native/fixtures/sample.html
Normal file
481
packages/common/native/fixtures/sample.html
Normal file
@@ -0,0 +1,481 @@
|
||||
<!doctype html>
|
||||
<!-- saved from url=(0020)https://example.org/ -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Example Domain</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #f0f0f2;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI',
|
||||
'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
div {
|
||||
width: 600px;
|
||||
margin: 5em auto;
|
||||
padding: 2em;
|
||||
background-color: #fdfdff;
|
||||
border-radius: 0.5em;
|
||||
box-shadow: 2px 3px 7px 2px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
a:link,
|
||||
a:visited {
|
||||
color: #38488f;
|
||||
text-decoration: none;
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
div {
|
||||
margin: 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Example Domain</h1>
|
||||
<p>
|
||||
This domain is for use in illustrative examples in documents. You may
|
||||
use this domain in literature without prior coordination or asking for
|
||||
permission.
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
href="https://www.iana.org/domains/example"
|
||||
rel="noreferrer"
|
||||
data-ss1736873651="1"
|
||||
>More information...</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
(function (
|
||||
canvas,
|
||||
canvasfont,
|
||||
audioblock,
|
||||
battery,
|
||||
webgl,
|
||||
webrtcdevice,
|
||||
gamepad,
|
||||
webvr,
|
||||
bluetooth,
|
||||
timezone,
|
||||
clientrects,
|
||||
clipboard,
|
||||
browserplugins
|
||||
) {
|
||||
function processFunctions(scope) {
|
||||
/* Browser Plugins */
|
||||
if (browserplugins == 'true') {
|
||||
scope.Object.defineProperty(navigator, 'plugins', {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: function () {
|
||||
var browserplugins_triggerblock =
|
||||
scope.document.createElement('div');
|
||||
browserplugins_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_browserplugins';
|
||||
browserplugins_triggerblock.title = 'navigator.plugins';
|
||||
document.documentElement.appendChild(browserplugins_triggerblock);
|
||||
return '';
|
||||
},
|
||||
});
|
||||
}
|
||||
/* Canvas */
|
||||
if (canvas != 'false') {
|
||||
var fakecanvas = scope.document.createElement('canvas');
|
||||
fakecanvas.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_canvas';
|
||||
if (canvas == 'random') {
|
||||
var fakewidth = (fakecanvas.width =
|
||||
Math.floor(Math.random() * 999) + 1);
|
||||
var fakeheight = (fakecanvas.height =
|
||||
Math.floor(Math.random() * 999) + 1);
|
||||
}
|
||||
var canvas_a = scope.HTMLCanvasElement;
|
||||
var origToDataURL = canvas_a.prototype.toDataURL;
|
||||
var origToBlob = canvas_a.prototype.toBlob;
|
||||
canvas_a.prototype.toDataURL = function () {
|
||||
fakecanvas.title = 'toDataURL';
|
||||
document.documentElement.appendChild(fakecanvas);
|
||||
if (canvas == 'block') return false;
|
||||
else if (canvas == 'blank') {
|
||||
fakecanvas.width = this.width;
|
||||
fakecanvas.height = this.height;
|
||||
return origToDataURL.apply(fakecanvas, arguments);
|
||||
} else if (canvas == 'random') {
|
||||
return origToDataURL.apply(fakecanvas, arguments);
|
||||
}
|
||||
};
|
||||
canvas_a.prototype.toBlob = function () {
|
||||
fakecanvas.title = 'toBlob';
|
||||
document.documentElement.appendChild(fakecanvas);
|
||||
if (canvas == 'block') return false;
|
||||
else if (canvas == 'blank') {
|
||||
fakecanvas.width = this.width;
|
||||
fakecanvas.height = this.height;
|
||||
return origToBlob.apply(fakecanvas, arguments);
|
||||
} else if (canvas == 'random') {
|
||||
return origToBlob.apply(fakecanvas, arguments);
|
||||
}
|
||||
};
|
||||
var canvas_b = scope.CanvasRenderingContext2D;
|
||||
var origGetImageData = canvas_b.prototype.getImageData;
|
||||
canvas_b.prototype.getImageData = function () {
|
||||
fakecanvas.title = 'getImageData';
|
||||
document.documentElement.appendChild(fakecanvas);
|
||||
if (canvas == 'block') return false;
|
||||
else if (canvas == 'blank') {
|
||||
fakecanvas.width = this.width;
|
||||
fakecanvas.height = this.height;
|
||||
return origGetImageData.apply(
|
||||
fakecanvas.getContext('2d'),
|
||||
arguments
|
||||
);
|
||||
} else if (canvas == 'random') {
|
||||
return origGetImageData.apply(fakecanvas.getContext('2d'), [
|
||||
Math.floor(Math.random() * fakewidth) + 1,
|
||||
Math.floor(Math.random() * fakeheight) + 1,
|
||||
Math.floor(Math.random() * fakewidth) + 1,
|
||||
Math.floor(Math.random() * fakeheight) + 1,
|
||||
]);
|
||||
}
|
||||
};
|
||||
var origGetLineDash = canvas_b.prototype.getLineDash;
|
||||
canvas_b.prototype.getLineDash = function () {
|
||||
fakecanvas.title = 'getLineDash';
|
||||
document.documentElement.appendChild(fakecanvas);
|
||||
if (canvas == 'block') return false;
|
||||
else if (canvas == 'blank') {
|
||||
fakecanvas.width = this.width;
|
||||
fakecanvas.height = this.height;
|
||||
return origGetLineDash.apply(fakecanvas.getContext('2d'), [0, 0]);
|
||||
} else if (canvas == 'random') {
|
||||
return origGetLineDash.apply(fakecanvas.getContext('2d'), [
|
||||
Math.floor(Math.random() * fakewidth) + 1,
|
||||
Math.floor(Math.random() * fakeheight) + 1,
|
||||
]);
|
||||
}
|
||||
};
|
||||
var canvas_c = scope.WebGLRenderingContext;
|
||||
var origReadPixels = canvas_c.prototype.readPixels;
|
||||
canvas_c.prototype.readPixels = function () {
|
||||
fakecanvas.title = 'readPixels';
|
||||
document.documentElement.appendChild(fakecanvas);
|
||||
if (canvas == 'block') return false;
|
||||
else if (canvas == 'blank') {
|
||||
fakecanvas.width = this.width;
|
||||
fakecanvas.height = this.height;
|
||||
return origReadPixels.apply(
|
||||
fakecanvas.getContext('webgl'),
|
||||
arguments
|
||||
);
|
||||
} else if (canvas == 'random') {
|
||||
return origReadPixels.apply(fakecanvas.getContext('webgl'), [
|
||||
Math.floor(Math.random() * fakewidth) + 1,
|
||||
Math.floor(Math.random() * fakeheight) + 1,
|
||||
Math.floor(Math.random() * fakewidth) + 1,
|
||||
Math.floor(Math.random() * fakeheight) + 1,
|
||||
arguments[4],
|
||||
arguments[5],
|
||||
arguments[6],
|
||||
]);
|
||||
}
|
||||
};
|
||||
}
|
||||
/* Audio Block */
|
||||
if (audioblock == 'true') {
|
||||
var audioblock_triggerblock = scope.document.createElement('div');
|
||||
audioblock_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_audio';
|
||||
var audioblock_a = scope.AudioBuffer;
|
||||
audioblock_a.prototype.copyFromChannel = function () {
|
||||
audioblock_triggerblock.title = 'copyFromChannel';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
audioblock_a.prototype.getChannelData = function () {
|
||||
audioblock_triggerblock.title = 'getChannelData';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
var audioblock_b = scope.AnalyserNode;
|
||||
audioblock_b.prototype.getFloatFrequencyData = function () {
|
||||
audioblock_triggerblock.title = 'getFloatFrequencyData';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
audioblock_b.prototype.getByteFrequencyData = function () {
|
||||
audioblock_triggerblock.title = 'getByteFrequencyData';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
audioblock_b.prototype.getFloatTimeDomainData = function () {
|
||||
audioblock_triggerblock.title = 'getFloatTimeDomainData';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
audioblock_b.prototype.getByteTimeDomainData = function () {
|
||||
audioblock_triggerblock.title = 'getByteTimeDomainData';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
var audioblock_c = scope;
|
||||
audioblock_c.AudioContext = function () {
|
||||
audioblock_triggerblock.title = 'AudioContext';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
audioblock_c.webkitAudioContext = function () {
|
||||
audioblock_triggerblock.title = 'webkitAudioContext';
|
||||
document.documentElement.appendChild(audioblock_triggerblock);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
/* Canvas Font */
|
||||
if (canvasfont == 'true') {
|
||||
var canvasfont_triggerblock = scope.document.createElement('div');
|
||||
canvasfont_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_canvasfont';
|
||||
var canvasfont_a = scope.CanvasRenderingContext2D;
|
||||
canvasfont_a.prototype.measureText = function () {
|
||||
canvasfont_triggerblock.title = 'measureText';
|
||||
document.documentElement.appendChild(canvasfont_triggerblock);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
/* Battery */
|
||||
if (battery == 'true') {
|
||||
var battery_triggerblock = scope.document.createElement('div');
|
||||
battery_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_battery';
|
||||
var battery_a = scope.navigator;
|
||||
battery_a.getBattery = function () {
|
||||
battery_triggerblock.title = 'getBattery';
|
||||
document.documentElement.appendChild(battery_triggerblock);
|
||||
return void 0;
|
||||
};
|
||||
}
|
||||
/* WebGL */
|
||||
if (webgl == 'true') {
|
||||
var webgl_triggerblock = scope.document.createElement('div');
|
||||
webgl_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_webgl';
|
||||
var webgl_a = scope.HTMLCanvasElement;
|
||||
var origGetContext = webgl_a.prototype.getContext;
|
||||
webgl_a.prototype.getContext = function (arg) {
|
||||
if (arg.match(/webgl/i)) {
|
||||
webgl_triggerblock.title = 'getContext';
|
||||
document.documentElement.appendChild(webgl_triggerblock);
|
||||
return false;
|
||||
}
|
||||
return origGetContext.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
/* WebRTC */
|
||||
if (webrtcdevice == 'true') {
|
||||
var webrtc_triggerblock = scope.document.createElement('div');
|
||||
webrtc_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_webrtc';
|
||||
var webrtc_a = scope.MediaStreamTrack;
|
||||
webrtc_a.getSources = function () {
|
||||
webrtc_triggerblock.title = 'getSources';
|
||||
document.documentElement.appendChild(webrtc_triggerblock);
|
||||
return false;
|
||||
};
|
||||
webrtc_a.getMediaDevices = function () {
|
||||
webrtc_triggerblock.title = 'getMediaDevices';
|
||||
document.documentElement.appendChild(webrtc_triggerblock);
|
||||
return false;
|
||||
};
|
||||
var webrtc_b = scope.navigator.mediaDevices;
|
||||
webrtc_b.enumerateDevices = function () {
|
||||
webrtc_triggerblock.title = 'enumerateDevices';
|
||||
document.documentElement.appendChild(webrtc_triggerblock);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
/* Gamepad */
|
||||
if (gamepad == 'true') {
|
||||
var gamepad_triggerblock = scope.document.createElement('div');
|
||||
gamepad_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_gamepad';
|
||||
var gamepad_a = scope.navigator;
|
||||
gamepad_a.getGamepads = function () {
|
||||
gamepad_triggerblock.title = 'getGamepads';
|
||||
document.documentElement.appendChild(gamepad_triggerblock);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
/* WebVR */
|
||||
if (webvr == 'true') {
|
||||
var webvr_triggerblock = scope.document.createElement('div');
|
||||
webvr_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_webvr';
|
||||
var webvr_a = scope.navigator;
|
||||
webvr_a.getVRDisplays = function () {
|
||||
webvr_triggerblock.title = 'getVRDisplays';
|
||||
document.documentElement.appendChild(webvr_triggerblock);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
/* Bluetooth */
|
||||
if (bluetooth == 'true') {
|
||||
if (scope.navigator.bluetooth) {
|
||||
var bluetooth_triggerblock = scope.document.createElement('div');
|
||||
bluetooth_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_bluetooth';
|
||||
var bluetooth_a = scope.navigator.bluetooth;
|
||||
bluetooth_a.requestDevice = function () {
|
||||
bluetooth_triggerblock.title = 'requestDevice';
|
||||
document.documentElement.appendChild(bluetooth_triggerblock);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
/* Client Rectangles */
|
||||
if (clientrects == 'true') {
|
||||
var clientrects_triggerblock = scope.document.createElement('div');
|
||||
clientrects_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_clientrects';
|
||||
Element.prototype.getClientRects = function () {
|
||||
clientrects_triggerblock.title = 'getClientRects';
|
||||
document.documentElement.appendChild(clientrects_triggerblock);
|
||||
return [
|
||||
{ top: 0, bottom: 0, left: 0, right: 0, height: 0, width: 0 },
|
||||
];
|
||||
};
|
||||
}
|
||||
/* Timezone */
|
||||
if (timezone != 'false') {
|
||||
var timezone_triggerblock = scope.document.createElement('div');
|
||||
timezone_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_timezone';
|
||||
var timezone_a = scope.Date;
|
||||
timezone_a.prototype.getTimezoneOffset = function () {
|
||||
timezone_triggerblock.title = 'getTimezoneOffset';
|
||||
document.documentElement.appendChild(timezone_triggerblock);
|
||||
if (timezone == 'random')
|
||||
return [
|
||||
'720',
|
||||
'660',
|
||||
'600',
|
||||
'570',
|
||||
'540',
|
||||
'480',
|
||||
'420',
|
||||
'360',
|
||||
'300',
|
||||
'240',
|
||||
'210',
|
||||
'180',
|
||||
'120',
|
||||
'60',
|
||||
'0',
|
||||
'-60',
|
||||
'-120',
|
||||
'-180',
|
||||
'-210',
|
||||
'-240',
|
||||
'-270',
|
||||
'-300',
|
||||
'-330',
|
||||
'-345',
|
||||
'-360',
|
||||
'-390',
|
||||
'-420',
|
||||
'-480',
|
||||
'-510',
|
||||
'-525',
|
||||
'-540',
|
||||
'-570',
|
||||
'-600',
|
||||
'-630',
|
||||
'-660',
|
||||
'-720',
|
||||
'-765',
|
||||
'-780',
|
||||
'-840',
|
||||
][Math.floor(Math.random() * 39)];
|
||||
return timezone;
|
||||
};
|
||||
}
|
||||
/* Clipboard */
|
||||
if (clipboard == 'true') {
|
||||
var clipboard_triggerblock = scope.document.createElement('div');
|
||||
clipboard_triggerblock.className =
|
||||
'scriptsafe_oiigbmnaadbkfbmpbfijlflahbdbdgdf_clipboard';
|
||||
var clipboard_a = document;
|
||||
var origExecCommand = clipboard_a.execCommand;
|
||||
clipboard_a.execCommand = function () {
|
||||
clipboard_triggerblock.title = 'execCommand';
|
||||
document.documentElement.appendChild(clipboard_triggerblock);
|
||||
if (arguments[0] == 'cut' || arguments[0] == 'copy') return false;
|
||||
return origExecCommand.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
processFunctions(window);
|
||||
var iwin = HTMLIFrameElement.prototype.__lookupGetter__('contentWindow'),
|
||||
idoc = HTMLIFrameElement.prototype.__lookupGetter__('contentDocument');
|
||||
Object.defineProperties(HTMLIFrameElement.prototype, {
|
||||
contentWindow: {
|
||||
get: function () {
|
||||
var frame = iwin.apply(this);
|
||||
if (
|
||||
this.src &&
|
||||
this.src.indexOf('//') != -1 &&
|
||||
location.host != this.src.split('/')[2]
|
||||
)
|
||||
return frame;
|
||||
try {
|
||||
frame.HTMLCanvasElement;
|
||||
} catch (err) {
|
||||
/* do nothing*/
|
||||
}
|
||||
processFunctions(frame);
|
||||
return frame;
|
||||
},
|
||||
},
|
||||
contentDocument: {
|
||||
get: function () {
|
||||
if (
|
||||
this.src &&
|
||||
this.src.indexOf('//') != -1 &&
|
||||
location.host != this.src.split('/')[2]
|
||||
)
|
||||
return idoc.apply(this);
|
||||
var frame = iwin.apply(this);
|
||||
try {
|
||||
frame.HTMLCanvasElement;
|
||||
} catch (err) {
|
||||
/* do nothing*/
|
||||
}
|
||||
processFunctions(frame);
|
||||
return idoc.apply(this);
|
||||
},
|
||||
},
|
||||
});
|
||||
})(
|
||||
'block',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'false',
|
||||
'true',
|
||||
'true',
|
||||
'true'
|
||||
);
|
||||
</script>
|
||||
</html>
|
||||
6
packages/common/native/fixtures/sample.html.0.md
Normal file
6
packages/common/native/fixtures/sample.html.0.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Example Domain
|
||||
|
||||
This domain is for use in illustrative examples in documents. You may
|
||||
use this domain in literature without prior coordination or asking for
|
||||
permission.
|
||||
More information...
|
||||
BIN
packages/common/native/fixtures/sample.pdf
Normal file
BIN
packages/common/native/fixtures/sample.pdf
Normal file
Binary file not shown.
40
packages/common/native/fixtures/sample.pdf.0.md
Normal file
40
packages/common/native/fixtures/sample.pdf.0.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Sample PDF
|
||||
This is a simple PDF file. Fun fun fun.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Phasellus facilisis odio sed mi.
|
||||
Curabitur suscipit. Nullam vel nisi. Etiam semper ipsum ut lectus. Proin aliquam, erat eget
|
||||
pharetra commodo, eros mi condimentum quam, sed commodo justo quam ut velit.
|
||||
Integer a erat. Cras laoreet ligula cursus enim. Aenean scelerisque velit et tellus.
|
||||
Vestibulum dictum aliquet sem. Nulla facilisi. Vestibulum accumsan ante vitae elit. Nulla
|
||||
erat dolor, blandit in, rutrum quis, semper pulvinar, enim. Nullam varius congue risus.
|
||||
Vivamus sollicitudin, metus ut interdum eleifend, nisi tellus pellentesque elit, tristique
|
||||
accumsan eros quam et risus. Suspendisse libero odio, mattis sit amet, aliquet eget,
|
||||
hendrerit vel, nulla. Sed vitae augue. Aliquam erat volutpat. Aliquam feugiat vulputate nisl.
|
||||
Suspendisse quis nulla pretium ante pretium mollis. Proin velit ligula, sagittis at, egestas a,
|
||||
pulvinar quis, nisl.
|
||||
|
||||
Pellentesque sit amet lectus. Praesent pulvinar, nunc quis iaculis sagittis, justo quam
|
||||
lobortis tortor, sed vestibulum dui metus venenatis est. Nunc cursus ligula. Nulla facilisi.
|
||||
Phasellus ullamcorper consectetuer ante. Duis tincidunt, urna id condimentum luctus, nibh
|
||||
ante vulputate sapien, id sagittis massa orci ut enim. Pellentesque vestibulum convallis
|
||||
sem. Nulla consequat quam ut nisl. Nullam est. Curabitur tincidunt dapibus lorem. Proin
|
||||
velit turpis, scelerisque sit amet, iaculis nec, rhoncus ac, ipsum. Phasellus lorem arcu,
|
||||
feugiat eu, gravida eu, consequat molestie, ipsum. Nullam vel est ut ipsum volutpat
|
||||
feugiat. Aenean pellentesque.
|
||||
|
||||
In mauris. Pellentesque dui nisi, iaculis eu, rhoncus in, venenatis ac, ante. Ut odio justo,
|
||||
scelerisque vel, facilisis non, commodo a, pede. Cras nec massa sit amet tortor volutpat
|
||||
varius. Donec lacinia, neque a luctus aliquet, pede massa imperdiet ante, at varius lorem
|
||||
pede sed sapien. Fusce erat nibh, aliquet in, eleifend eget, commodo eget, erat. Fusce
|
||||
consectetuer. Cras risus tortor, porttitor nec, tristique sed, convallis semper, eros. Fusce
|
||||
vulputate ipsum a mauris. Phasellus mollis. Curabitur sed urna. Aliquam nec sapien non
|
||||
nibh pulvinar convallis. Vivamus facilisis augue quis quam. Proin cursus aliquet metus.
|
||||
Suspendisse lacinia. Nulla at tellus ac turpis eleifend scelerisque. Maecenas a pede vitae
|
||||
enim commodo interdum. Donec odio. Sed sollicitudin dui vitae justo.
|
||||
|
||||
Morbi elit nunc, facilisis a, mollis a, molestie at, lectus. Suspendisse eget mauris eu tellus
|
||||
molestie cursus. Duis ut magna at justo dignissim condimentum. Cum sociis natoque
|
||||
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus varius. Ut sit
|
||||
amet diam suscipit mauris ornare aliquam. Sed varius. Duis arcu. Etiam tristique massa
|
||||
eget dui. Phasellus congue. Aenean est erat, tincidunt eget, venenatis quis, commodo at,
|
||||
quam.
|
||||
9
packages/common/native/fixtures/sample.pdf.1.md
Normal file
9
packages/common/native/fixtures/sample.pdf.1.md
Normal file
@@ -0,0 +1,9 @@
|
||||
Pellentesque sit amet lectus. Praesent pulvinar, nunc quis iaculis sagittis, justo quam
|
||||
lobortis tortor, sed vestibulum dui metus venenatis est. Nunc cursus ligula. Nulla facilisi.
|
||||
Phasellus ullamcorper consectetuer ante. Duis tincidunt, urna id condimentum luctus, nibh
|
||||
ante vulputate sapien, id sagittis massa orci ut enim. Pellentesque vestibulum convallis
|
||||
sem. Nulla consequat quam ut nisl. Nullam est. Curabitur tincidunt dapibus lorem. Proin
|
||||
velit turpis, scelerisque sit amet, iaculis nec, rhoncus ac, ipsum. Phasellus lorem arcu,
|
||||
feugiat eu, gravida eu, consequat molestie, ipsum. Nullam vel est ut ipsum volutpat
|
||||
feugiat. Aenean pellentesque.
|
||||
|
||||
16
packages/common/native/fixtures/sample.pdf.2.md
Normal file
16
packages/common/native/fixtures/sample.pdf.2.md
Normal file
@@ -0,0 +1,16 @@
|
||||
In mauris. Pellentesque dui nisi, iaculis eu, rhoncus in, venenatis ac, ante. Ut odio justo,
|
||||
scelerisque vel, facilisis non, commodo a, pede. Cras nec massa sit amet tortor volutpat
|
||||
varius. Donec lacinia, neque a luctus aliquet, pede massa imperdiet ante, at varius lorem
|
||||
pede sed sapien. Fusce erat nibh, aliquet in, eleifend eget, commodo eget, erat. Fusce
|
||||
consectetuer. Cras risus tortor, porttitor nec, tristique sed, convallis semper, eros. Fusce
|
||||
vulputate ipsum a mauris. Phasellus mollis. Curabitur sed urna. Aliquam nec sapien non
|
||||
nibh pulvinar convallis. Vivamus facilisis augue quis quam. Proin cursus aliquet metus.
|
||||
Suspendisse lacinia. Nulla at tellus ac turpis eleifend scelerisque. Maecenas a pede vitae
|
||||
enim commodo interdum. Donec odio. Sed sollicitudin dui vitae justo.
|
||||
|
||||
Morbi elit nunc, facilisis a, mollis a, molestie at, lectus. Suspendisse eget mauris eu tellus
|
||||
molestie cursus. Duis ut magna at justo dignissim condimentum. Cum sociis natoque
|
||||
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus varius. Ut sit
|
||||
amet diam suscipit mauris ornare aliquam. Sed varius. Duis arcu. Etiam tristique massa
|
||||
eget dui. Phasellus congue. Aenean est erat, tincidunt eget, venenatis quis, commodo at,
|
||||
quam.
|
||||
10
packages/common/native/fixtures/sample.rs
Normal file
10
packages/common/native/fixtures/sample.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
fn factorial(n: u64) -> u64 {
|
||||
if n == 0 {
|
||||
return 1;
|
||||
}
|
||||
n * factorial(n - 1)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
6
packages/common/native/fixtures/sample.rs.0.md
Normal file
6
packages/common/native/fixtures/sample.rs.0.md
Normal file
@@ -0,0 +1,6 @@
|
||||
fn factorial(n: u64) -> u64 {
|
||||
if n == 0 {
|
||||
return 1;
|
||||
}
|
||||
n * factorial(n - 1)
|
||||
}
|
||||
3
packages/common/native/fixtures/sample.rs.1.md
Normal file
3
packages/common/native/fixtures/sample.rs.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
3
packages/common/native/fixtures/sample.ts
Normal file
3
packages/common/native/fixtures/sample.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function sample() {
|
||||
return 'sample';
|
||||
}
|
||||
3
packages/common/native/fixtures/sample.ts.0.md
Normal file
3
packages/common/native/fixtures/sample.ts.0.md
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function sample() {
|
||||
return 'sample';
|
||||
}
|
||||
175
packages/common/native/src/hashcash.rs
Normal file
175
packages/common/native/src/hashcash.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
|
||||
use rand::{
|
||||
distr::{Alphanumeric, Distribution},
|
||||
rng,
|
||||
};
|
||||
use sha3::{Digest, Sha3_256};
|
||||
|
||||
const SALT_LENGTH: usize = 16;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stamp {
|
||||
version: String,
|
||||
claim: u32,
|
||||
ts: String,
|
||||
resource: String,
|
||||
ext: String,
|
||||
rand: String,
|
||||
counter: String,
|
||||
}
|
||||
|
||||
impl Stamp {
|
||||
fn check_expiration(&self) -> bool {
|
||||
NaiveDateTime::parse_from_str(&self.ts, "%Y%m%d%H%M%S")
|
||||
.ok()
|
||||
.map(|ts| DateTime::<Utc>::from_naive_utc_and_offset(ts, Utc))
|
||||
.and_then(|utc| {
|
||||
utc
|
||||
.checked_add_signed(Duration::minutes(5))
|
||||
.map(|utc| Utc::now() <= utc)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn check<S: AsRef<str>>(&self, bits: u32, resource: S) -> bool {
|
||||
if self.version == "1" && bits <= self.claim && self.check_expiration() && self.resource == resource.as_ref() {
|
||||
let hex_digits = ((self.claim as f32) / 4.).floor() as usize;
|
||||
|
||||
// check challenge
|
||||
let mut hasher = Sha3_256::new();
|
||||
hasher.update(self.format().as_bytes());
|
||||
let result = hex::encode(hasher.finalize());
|
||||
result[..hex_digits] == String::from_utf8(vec![b'0'; hex_digits]).unwrap()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(&self) -> String {
|
||||
format!(
|
||||
"{}:{}:{}:{}:{}:{}:{}",
|
||||
self.version, self.claim, self.ts, self.resource, self.ext, self.rand, self.counter
|
||||
)
|
||||
}
|
||||
|
||||
/// Mint a new hashcash stamp.
|
||||
pub fn mint(resource: String, bits: Option<u32>) -> Self {
|
||||
let version = "1";
|
||||
let now = Utc::now();
|
||||
let ts = now.format("%Y%m%d%H%M%S");
|
||||
let bits = bits.unwrap_or(20);
|
||||
let rand = String::from_iter(Alphanumeric.sample_iter(rng()).take(SALT_LENGTH).map(char::from));
|
||||
let challenge = format!("{}:{}:{}:{}:{}:{}", version, bits, ts, resource, "", rand);
|
||||
|
||||
Stamp {
|
||||
version: version.to_string(),
|
||||
claim: bits,
|
||||
ts: ts.to_string(),
|
||||
resource,
|
||||
ext: "".to_string(),
|
||||
rand,
|
||||
counter: {
|
||||
let mut hasher = Sha3_256::new();
|
||||
let mut counter = 0;
|
||||
let hex_digits = ((bits as f32) / 4.).ceil() as usize;
|
||||
let zeros = String::from_utf8(vec![b'0'; hex_digits]).unwrap();
|
||||
loop {
|
||||
hasher.update(format!("{challenge}:{counter:x}").as_bytes());
|
||||
let result = hex::encode(hasher.finalize_reset());
|
||||
if result[..hex_digits] == zeros {
|
||||
break format!("{counter:x}");
|
||||
};
|
||||
counter += 1
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Stamp {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let stamp_vec = value.split(':').collect::<Vec<&str>>();
|
||||
if stamp_vec.len() != 7 || stamp_vec.iter().enumerate().any(|(i, s)| i != 4 && s.is_empty()) {
|
||||
return Err(format!("Malformed stamp, expected 6 parts, got {}", stamp_vec.len()));
|
||||
}
|
||||
Ok(Stamp {
|
||||
version: stamp_vec[0].to_string(),
|
||||
claim: stamp_vec[1].parse().map_err(|_| "Malformed stamp".to_string())?,
|
||||
ts: stamp_vec[2].to_string(),
|
||||
resource: stamp_vec[3].to_string(),
|
||||
ext: stamp_vec[4].to_string(),
|
||||
rand: stamp_vec[5].to_string(),
|
||||
counter: stamp_vec[6].to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::{Rng, distr::Alphanumeric};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use super::Stamp;
|
||||
|
||||
#[test]
|
||||
fn test_mint() {
|
||||
{
|
||||
let response = Stamp::mint("test".into(), Some(20)).format();
|
||||
assert!(
|
||||
Stamp::try_from(response.as_str()).unwrap().check(20, "test"),
|
||||
"should pass"
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let response = Stamp::mint("test".into(), Some(19)).format();
|
||||
assert!(
|
||||
!Stamp::try_from(response.as_str()).unwrap().check(20, "test"),
|
||||
"should fail with lower bits"
|
||||
);
|
||||
}
|
||||
{
|
||||
let response = Stamp::mint("test".into(), Some(20)).format();
|
||||
assert!(
|
||||
!Stamp::try_from(response.as_str()).unwrap().check(20, "test2"),
|
||||
"should fail with different resource"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_expiration() {
|
||||
let response = Stamp::mint("test".into(), Some(20));
|
||||
assert!(response.check_expiration());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format() {
|
||||
let response = Stamp::mint("test".into(), Some(20));
|
||||
assert_eq!(
|
||||
response.format(),
|
||||
format!("1:20:{}:test::{}:{}", response.ts, response.rand, response.counter)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fuzz() {
|
||||
(0..1000).into_par_iter().for_each(|_| {
|
||||
let bit = rand::random::<u32>() % 20 + 1;
|
||||
let resource = rand::rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(7)
|
||||
.map(char::from)
|
||||
.collect::<String>();
|
||||
let response = Stamp::mint(resource.clone(), Some(bit)).format();
|
||||
assert!(
|
||||
Stamp::try_from(response.as_str()).unwrap().check(bit, resource),
|
||||
"should pass"
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
4
packages/common/native/src/lib.rs
Normal file
4
packages/common/native/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[cfg(feature = "hashcash")]
|
||||
pub mod hashcash;
|
||||
#[cfg(feature = "napi")]
|
||||
pub mod napi_utils;
|
||||
22
packages/common/native/src/napi_utils.rs
Normal file
22
packages/common/native/src/napi_utils.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use napi::{Error, Result, Status};
|
||||
|
||||
pub fn to_napi_error<E: Display + Debug>(err: E, status: Status) -> Error {
|
||||
Error::new(status, err.to_string())
|
||||
}
|
||||
|
||||
pub fn map_napi_err<T, E: Display + Debug>(value: std::result::Result<T, E>, status: Status) -> Result<T> {
|
||||
value.map_err(|err| to_napi_error(err, status))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn map_napi_err_keeps_message() {
|
||||
let err = map_napi_err::<(), _>(Err("boom"), Status::GenericFailure).unwrap_err();
|
||||
assert!(err.to_string().contains("boom"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user