Merge branch 'master' into travis/msc/global-versioning

pull/977/head
Travis Ralston 4 years ago
commit 8d6642aaa7

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Client-Server Capabiltiies API" title: "Matrix Client-Server Capabilities API"
version: "1.0.0" version: "1.0.0"
host: localhost:8008 host: localhost:8008
schemes: schemes:

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Document how clients can advise recipients that it is withholding decryption keys as per `MSC2399 <https://github.com/matrix-org/matrix-doc/pull/2399>`_.

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1 @@
Fix various typos throughout the specification.

@ -0,0 +1,66 @@
{
"Pin": "Кабърче",
"Folder": "Папка",
"Headphones": "Слушалки",
"Anchor": "Котва",
"Bell": "Звънец",
"Trumpet": "Тромпет",
"Guitar": "Китара",
"Ball": "Топка",
"Trophy": "Трофей",
"Rocket": "Ракета",
"Aeroplane": "Самолет",
"Bicycle": "Колело",
"Train": "Влак",
"Flag": "Флаг",
"Telephone": "Телефон",
"Hammer": "Чук",
"Key": "Ключ",
"Lock": "Катинар",
"Scissors": "Ножици",
"Paperclip": "Кламер",
"Pencil": "Молив",
"Book": "Книга",
"Light Bulb": "Лампа",
"Gift": "Подарък",
"Clock": "Часовник",
"Hourglass": "Пясъчен часовник",
"Umbrella": "Чадър",
"Thumbs Up": "Палец нагоре",
"Santa": "Дядо Коледа",
"Spanner": "Гаечен ключ",
"Glasses": "Очила",
"Hat": "Шапка",
"Robot": "Робот",
"Smiley": "Усмивка",
"Heart": "Сърце",
"Cake": "Торта",
"Pizza": "Пица",
"Corn": "Царевица",
"Strawberry": "Ягода",
"Apple": "Ябълка",
"Banana": "Банан",
"Fire": "Огън",
"Cloud": "Облак",
"Moon": "Луна",
"Globe": "Глобус",
"Mushroom": "Гъба",
"Cactus": "Кактус",
"Tree": "Дърво",
"Flower": "Цвете",
"Butterfly": "Пеперуда",
"Octopus": "Октопод",
"Fish": "Риба",
"Turtle": "Костенурка",
"Penguin": "Пингвин",
"Rooster": "Петел",
"Panda": "Панда",
"Rabbit": "Заек",
"Elephant": "Слон",
"Pig": "Прасе",
"Unicorn": "Еднорог",
"Horse": "Кон",
"Lion": "Лъв",
"Cat": "Котка",
"Dog": "Куче"
}

@ -0,0 +1,66 @@
{
"Cactus": "Cactus",
"Globe": "Globus terraqüi",
"Rooster": "Gall",
"Pin": "Xinxeta",
"Folder": "Carpeta",
"Headphones": "Auriculars",
"Anchor": "Àncora",
"Bell": "Campana",
"Trumpet": "Trompeta",
"Guitar": "Guitarra",
"Ball": "Pilota",
"Trophy": "Trofeu",
"Rocket": "Coet",
"Aeroplane": "Avió",
"Bicycle": "Bicicleta",
"Train": "Tren",
"Flag": "Bandera",
"Telephone": "Telèfon",
"Hammer": "Martell",
"Lock": "Cadenat",
"Key": "Clau",
"Scissors": "Tisores",
"Paperclip": "Clip",
"Pencil": "Llapis",
"Book": "Llibre",
"Light Bulb": "Bombeta",
"Gift": "Regal",
"Clock": "Rellotge",
"Hourglass": "Rellotge de sorra",
"Umbrella": "Paraigües",
"Thumbs Up": "Polzes amunt",
"Santa": "Pare Noél",
"Spanner": "Clau anglesa",
"Glasses": "Ulleres",
"Hat": "Barret",
"Robot": "Robot",
"Smiley": "Somrient",
"Heart": "Cor",
"Cake": "Pastís",
"Pizza": "Pizza",
"Corn": "Blat de moro",
"Strawberry": "Maduixa",
"Apple": "Poma",
"Banana": "Plàtan",
"Fire": "Foc",
"Cloud": "Núvol",
"Moon": "Lluna",
"Mushroom": "Bolet",
"Tree": "Arbre",
"Flower": "Flor",
"Butterfly": "Papallona",
"Octopus": "Pop",
"Fish": "Peix",
"Turtle": "Tortuga",
"Penguin": "Pingüí",
"Panda": "Panda",
"Rabbit": "Conill",
"Elephant": "Elefant",
"Unicorn": "Unicorn",
"Pig": "Porc",
"Horse": "Cavall",
"Lion": "Lleó",
"Cat": "Gat",
"Dog": "Gos"
}

@ -5,6 +5,8 @@
"description": "Dog", "description": "Dog",
"unicode": "U+1F436", "unicode": "U+1F436",
"translated_descriptions": { "translated_descriptions": {
"bg": "Куче",
"ca": "Gos",
"de": "Hund", "de": "Hund",
"eo": "Hundo", "eo": "Hundo",
"es": "Perro", "es": "Perro",
@ -29,6 +31,8 @@
"description": "Cat", "description": "Cat",
"unicode": "U+1F431", "unicode": "U+1F431",
"translated_descriptions": { "translated_descriptions": {
"bg": "Котка",
"ca": "Gat",
"de": "Katze", "de": "Katze",
"eo": "Kato", "eo": "Kato",
"es": "Gato", "es": "Gato",
@ -53,6 +57,8 @@
"description": "Lion", "description": "Lion",
"unicode": "U+1F981", "unicode": "U+1F981",
"translated_descriptions": { "translated_descriptions": {
"bg": "Лъв",
"ca": "Lleó",
"de": "Löwe", "de": "Löwe",
"eo": "Leono", "eo": "Leono",
"es": "León", "es": "León",
@ -77,6 +83,8 @@
"description": "Horse", "description": "Horse",
"unicode": "U+1F40E", "unicode": "U+1F40E",
"translated_descriptions": { "translated_descriptions": {
"bg": "Кон",
"ca": "Cavall",
"de": "Pferd", "de": "Pferd",
"eo": "Ĉevalo", "eo": "Ĉevalo",
"es": "Caballo", "es": "Caballo",
@ -101,6 +109,8 @@
"description": "Unicorn", "description": "Unicorn",
"unicode": "U+1F984", "unicode": "U+1F984",
"translated_descriptions": { "translated_descriptions": {
"bg": "Еднорог",
"ca": "Unicorn",
"de": "Einhorn", "de": "Einhorn",
"eo": "Unukorno", "eo": "Unukorno",
"es": "Unicornio", "es": "Unicornio",
@ -125,6 +135,8 @@
"description": "Pig", "description": "Pig",
"unicode": "U+1F437", "unicode": "U+1F437",
"translated_descriptions": { "translated_descriptions": {
"bg": "Прасе",
"ca": "Porc",
"de": "Schwein", "de": "Schwein",
"eo": "Porko", "eo": "Porko",
"es": "Cerdo", "es": "Cerdo",
@ -149,6 +161,8 @@
"description": "Elephant", "description": "Elephant",
"unicode": "U+1F418", "unicode": "U+1F418",
"translated_descriptions": { "translated_descriptions": {
"bg": "Слон",
"ca": "Elefant",
"de": "Elefant", "de": "Elefant",
"eo": "Elefanto", "eo": "Elefanto",
"es": "Elefante", "es": "Elefante",
@ -173,6 +187,8 @@
"description": "Rabbit", "description": "Rabbit",
"unicode": "U+1F430", "unicode": "U+1F430",
"translated_descriptions": { "translated_descriptions": {
"bg": "Заек",
"ca": "Conill",
"de": "Hase", "de": "Hase",
"eo": "Kuniklo", "eo": "Kuniklo",
"es": "Conejo", "es": "Conejo",
@ -197,6 +213,8 @@
"description": "Panda", "description": "Panda",
"unicode": "U+1F43C", "unicode": "U+1F43C",
"translated_descriptions": { "translated_descriptions": {
"bg": "Панда",
"ca": "Panda",
"de": "Panda", "de": "Panda",
"eo": "Pando", "eo": "Pando",
"es": "Panda", "es": "Panda",
@ -221,6 +239,8 @@
"description": "Rooster", "description": "Rooster",
"unicode": "U+1F413", "unicode": "U+1F413",
"translated_descriptions": { "translated_descriptions": {
"bg": "Петел",
"ca": "Gall",
"de": "Hahn", "de": "Hahn",
"eo": "Virkoko", "eo": "Virkoko",
"es": "Gallo", "es": "Gallo",
@ -245,6 +265,8 @@
"description": "Penguin", "description": "Penguin",
"unicode": "U+1F427", "unicode": "U+1F427",
"translated_descriptions": { "translated_descriptions": {
"bg": "Пингвин",
"ca": "Pingüí",
"de": "Pinguin", "de": "Pinguin",
"eo": "Pingveno", "eo": "Pingveno",
"es": "Pingüino", "es": "Pingüino",
@ -269,6 +291,8 @@
"description": "Turtle", "description": "Turtle",
"unicode": "U+1F422", "unicode": "U+1F422",
"translated_descriptions": { "translated_descriptions": {
"bg": "Костенурка",
"ca": "Tortuga",
"de": "Schildkröte", "de": "Schildkröte",
"eo": "Testudo", "eo": "Testudo",
"es": "Tortuga", "es": "Tortuga",
@ -293,6 +317,8 @@
"description": "Fish", "description": "Fish",
"unicode": "U+1F41F", "unicode": "U+1F41F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Риба",
"ca": "Peix",
"de": "Fisch", "de": "Fisch",
"eo": "Fiŝo", "eo": "Fiŝo",
"es": "Pez", "es": "Pez",
@ -317,6 +343,8 @@
"description": "Octopus", "description": "Octopus",
"unicode": "U+1F419", "unicode": "U+1F419",
"translated_descriptions": { "translated_descriptions": {
"bg": "Октопод",
"ca": "Pop",
"de": "Oktopus", "de": "Oktopus",
"eo": "Polpo", "eo": "Polpo",
"es": "Pulpo", "es": "Pulpo",
@ -341,6 +369,8 @@
"description": "Butterfly", "description": "Butterfly",
"unicode": "U+1F98B", "unicode": "U+1F98B",
"translated_descriptions": { "translated_descriptions": {
"bg": "Пеперуда",
"ca": "Papallona",
"de": "Schmetterling", "de": "Schmetterling",
"eo": "Papilio", "eo": "Papilio",
"es": "Mariposa", "es": "Mariposa",
@ -365,6 +395,8 @@
"description": "Flower", "description": "Flower",
"unicode": "U+1F337", "unicode": "U+1F337",
"translated_descriptions": { "translated_descriptions": {
"bg": "Цвете",
"ca": "Flor",
"de": "Blume", "de": "Blume",
"eo": "Floro", "eo": "Floro",
"es": "Flor", "es": "Flor",
@ -389,6 +421,8 @@
"description": "Tree", "description": "Tree",
"unicode": "U+1F333", "unicode": "U+1F333",
"translated_descriptions": { "translated_descriptions": {
"bg": "Дърво",
"ca": "Arbre",
"de": "Baum", "de": "Baum",
"eo": "Arbo", "eo": "Arbo",
"es": "Árbol", "es": "Árbol",
@ -413,6 +447,8 @@
"description": "Cactus", "description": "Cactus",
"unicode": "U+1F335", "unicode": "U+1F335",
"translated_descriptions": { "translated_descriptions": {
"bg": "Кактус",
"ca": "Cactus",
"de": "Kaktus", "de": "Kaktus",
"eo": "Kakto", "eo": "Kakto",
"es": "Cactus", "es": "Cactus",
@ -437,6 +473,8 @@
"description": "Mushroom", "description": "Mushroom",
"unicode": "U+1F344", "unicode": "U+1F344",
"translated_descriptions": { "translated_descriptions": {
"bg": "Гъба",
"ca": "Bolet",
"de": "Pilz", "de": "Pilz",
"eo": "Fungo", "eo": "Fungo",
"es": "Seta", "es": "Seta",
@ -461,6 +499,8 @@
"description": "Globe", "description": "Globe",
"unicode": "U+1F30F", "unicode": "U+1F30F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Глобус",
"ca": "Globus terraqüi",
"de": "Globus", "de": "Globus",
"eo": "Globo", "eo": "Globo",
"es": "Globo", "es": "Globo",
@ -485,6 +525,8 @@
"description": "Moon", "description": "Moon",
"unicode": "U+1F319", "unicode": "U+1F319",
"translated_descriptions": { "translated_descriptions": {
"bg": "Луна",
"ca": "Lluna",
"de": "Mond", "de": "Mond",
"eo": "Luno", "eo": "Luno",
"es": "Luna", "es": "Luna",
@ -509,6 +551,8 @@
"description": "Cloud", "description": "Cloud",
"unicode": "U+2601U+FE0F", "unicode": "U+2601U+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Облак",
"ca": "Núvol",
"de": "Wolke", "de": "Wolke",
"eo": "Nubo", "eo": "Nubo",
"es": "Nube", "es": "Nube",
@ -533,6 +577,8 @@
"description": "Fire", "description": "Fire",
"unicode": "U+1F525", "unicode": "U+1F525",
"translated_descriptions": { "translated_descriptions": {
"bg": "Огън",
"ca": "Foc",
"de": "Feuer", "de": "Feuer",
"eo": "Fajro", "eo": "Fajro",
"es": "Fuego", "es": "Fuego",
@ -557,6 +603,8 @@
"description": "Banana", "description": "Banana",
"unicode": "U+1F34C", "unicode": "U+1F34C",
"translated_descriptions": { "translated_descriptions": {
"bg": "Банан",
"ca": "Plàtan",
"de": "Banane", "de": "Banane",
"eo": "Banano", "eo": "Banano",
"es": "Plátano", "es": "Plátano",
@ -581,6 +629,8 @@
"description": "Apple", "description": "Apple",
"unicode": "U+1F34E", "unicode": "U+1F34E",
"translated_descriptions": { "translated_descriptions": {
"bg": "Ябълка",
"ca": "Poma",
"de": "Apfel", "de": "Apfel",
"eo": "Pomo", "eo": "Pomo",
"es": "Manzana", "es": "Manzana",
@ -605,6 +655,8 @@
"description": "Strawberry", "description": "Strawberry",
"unicode": "U+1F353", "unicode": "U+1F353",
"translated_descriptions": { "translated_descriptions": {
"bg": "Ягода",
"ca": "Maduixa",
"de": "Erdbeere", "de": "Erdbeere",
"eo": "Frago", "eo": "Frago",
"es": "Fresa", "es": "Fresa",
@ -629,6 +681,8 @@
"description": "Corn", "description": "Corn",
"unicode": "U+1F33D", "unicode": "U+1F33D",
"translated_descriptions": { "translated_descriptions": {
"bg": "Царевица",
"ca": "Blat de moro",
"de": "Korn", "de": "Korn",
"eo": "Maizo", "eo": "Maizo",
"es": "Maíz", "es": "Maíz",
@ -653,6 +707,8 @@
"description": "Pizza", "description": "Pizza",
"unicode": "U+1F355", "unicode": "U+1F355",
"translated_descriptions": { "translated_descriptions": {
"bg": "Пица",
"ca": "Pizza",
"de": "Pizza", "de": "Pizza",
"eo": "Pico", "eo": "Pico",
"es": "Pizza", "es": "Pizza",
@ -677,6 +733,8 @@
"description": "Cake", "description": "Cake",
"unicode": "U+1F382", "unicode": "U+1F382",
"translated_descriptions": { "translated_descriptions": {
"bg": "Торта",
"ca": "Pastís",
"de": "Kuchen", "de": "Kuchen",
"eo": "Torto", "eo": "Torto",
"es": "Tarta", "es": "Tarta",
@ -701,6 +759,8 @@
"description": "Heart", "description": "Heart",
"unicode": "U+2764U+FE0F", "unicode": "U+2764U+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Сърце",
"ca": "Cor",
"de": "Herz", "de": "Herz",
"eo": "Koro", "eo": "Koro",
"es": "Corazón", "es": "Corazón",
@ -725,6 +785,8 @@
"description": "Smiley", "description": "Smiley",
"unicode": "U+1F600", "unicode": "U+1F600",
"translated_descriptions": { "translated_descriptions": {
"bg": "Усмивка",
"ca": "Somrient",
"de": "Smiley", "de": "Smiley",
"eo": "Rideto", "eo": "Rideto",
"es": "Emoticono", "es": "Emoticono",
@ -749,6 +811,8 @@
"description": "Robot", "description": "Robot",
"unicode": "U+1F916", "unicode": "U+1F916",
"translated_descriptions": { "translated_descriptions": {
"bg": "Робот",
"ca": "Robot",
"de": "Roboter", "de": "Roboter",
"eo": "Roboto", "eo": "Roboto",
"es": "Robot", "es": "Robot",
@ -773,6 +837,8 @@
"description": "Hat", "description": "Hat",
"unicode": "U+1F3A9", "unicode": "U+1F3A9",
"translated_descriptions": { "translated_descriptions": {
"bg": "Шапка",
"ca": "Barret",
"de": "Hut", "de": "Hut",
"eo": "Ĉapelo", "eo": "Ĉapelo",
"es": "Sombrero", "es": "Sombrero",
@ -797,6 +863,8 @@
"description": "Glasses", "description": "Glasses",
"unicode": "U+1F453", "unicode": "U+1F453",
"translated_descriptions": { "translated_descriptions": {
"bg": "Очила",
"ca": "Ulleres",
"de": "Brille", "de": "Brille",
"eo": "Okulvitroj", "eo": "Okulvitroj",
"es": "Gafas", "es": "Gafas",
@ -821,6 +889,8 @@
"description": "Spanner", "description": "Spanner",
"unicode": "U+1F527", "unicode": "U+1F527",
"translated_descriptions": { "translated_descriptions": {
"bg": "Гаечен ключ",
"ca": "Clau anglesa",
"de": "Schraubenschlüssel", "de": "Schraubenschlüssel",
"eo": "Ŝraŭbŝlosilo", "eo": "Ŝraŭbŝlosilo",
"es": "Llave inglesa", "es": "Llave inglesa",
@ -845,6 +915,8 @@
"description": "Santa", "description": "Santa",
"unicode": "U+1F385", "unicode": "U+1F385",
"translated_descriptions": { "translated_descriptions": {
"bg": "Дядо Коледа",
"ca": "Pare Noél",
"de": "Nikolaus", "de": "Nikolaus",
"eo": "Kristnaska viro", "eo": "Kristnaska viro",
"es": null, "es": null,
@ -869,6 +941,8 @@
"description": "Thumbs Up", "description": "Thumbs Up",
"unicode": "U+1F44D", "unicode": "U+1F44D",
"translated_descriptions": { "translated_descriptions": {
"bg": "Палец нагоре",
"ca": "Polzes amunt",
"de": "Daumen Hoch", "de": "Daumen Hoch",
"eo": "Dikfingro supren", "eo": "Dikfingro supren",
"es": null, "es": null,
@ -893,6 +967,8 @@
"description": "Umbrella", "description": "Umbrella",
"unicode": "U+2602U+FE0F", "unicode": "U+2602U+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Чадър",
"ca": "Paraigües",
"de": "Regenschirm", "de": "Regenschirm",
"eo": "Ombrelo", "eo": "Ombrelo",
"es": null, "es": null,
@ -917,6 +993,8 @@
"description": "Hourglass", "description": "Hourglass",
"unicode": "U+231B", "unicode": "U+231B",
"translated_descriptions": { "translated_descriptions": {
"bg": "Пясъчен часовник",
"ca": "Rellotge de sorra",
"de": "Sanduhr", "de": "Sanduhr",
"eo": "Sablohorloĝo", "eo": "Sablohorloĝo",
"es": null, "es": null,
@ -941,6 +1019,8 @@
"description": "Clock", "description": "Clock",
"unicode": "U+23F0", "unicode": "U+23F0",
"translated_descriptions": { "translated_descriptions": {
"bg": "Часовник",
"ca": "Rellotge",
"de": "Wecker", "de": "Wecker",
"eo": "Horloĝo", "eo": "Horloĝo",
"es": "Reloj", "es": "Reloj",
@ -965,6 +1045,8 @@
"description": "Gift", "description": "Gift",
"unicode": "U+1F381", "unicode": "U+1F381",
"translated_descriptions": { "translated_descriptions": {
"bg": "Подарък",
"ca": "Regal",
"de": "Geschenk", "de": "Geschenk",
"eo": "Donaco", "eo": "Donaco",
"es": "Regalo", "es": "Regalo",
@ -989,6 +1071,8 @@
"description": "Light Bulb", "description": "Light Bulb",
"unicode": "U+1F4A1", "unicode": "U+1F4A1",
"translated_descriptions": { "translated_descriptions": {
"bg": "Лампа",
"ca": "Bombeta",
"de": "Glühbirne", "de": "Glühbirne",
"eo": "Lampo", "eo": "Lampo",
"es": null, "es": null,
@ -1013,6 +1097,8 @@
"description": "Book", "description": "Book",
"unicode": "U+1F4D5", "unicode": "U+1F4D5",
"translated_descriptions": { "translated_descriptions": {
"bg": "Книга",
"ca": "Llibre",
"de": "Buch", "de": "Buch",
"eo": "Libro", "eo": "Libro",
"es": "Libro", "es": "Libro",
@ -1037,6 +1123,8 @@
"description": "Pencil", "description": "Pencil",
"unicode": "U+270FU+FE0F", "unicode": "U+270FU+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Молив",
"ca": "Llapis",
"de": "Bleistift", "de": "Bleistift",
"eo": "Krajono", "eo": "Krajono",
"es": "Lápiz", "es": "Lápiz",
@ -1061,6 +1149,8 @@
"description": "Paperclip", "description": "Paperclip",
"unicode": "U+1F4CE", "unicode": "U+1F4CE",
"translated_descriptions": { "translated_descriptions": {
"bg": "Кламер",
"ca": "Clip",
"de": "Büroklammer", "de": "Büroklammer",
"eo": "Paperkuntenilo", "eo": "Paperkuntenilo",
"es": null, "es": null,
@ -1085,6 +1175,8 @@
"description": "Scissors", "description": "Scissors",
"unicode": "U+2702U+FE0F", "unicode": "U+2702U+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Ножици",
"ca": "Tisores",
"de": "Schere", "de": "Schere",
"eo": "Tondilo", "eo": "Tondilo",
"es": null, "es": null,
@ -1109,6 +1201,8 @@
"description": "Lock", "description": "Lock",
"unicode": "U+1F512", "unicode": "U+1F512",
"translated_descriptions": { "translated_descriptions": {
"bg": "Катинар",
"ca": "Cadenat",
"de": "Schloss", "de": "Schloss",
"eo": "Seruro", "eo": "Seruro",
"es": null, "es": null,
@ -1133,6 +1227,8 @@
"description": "Key", "description": "Key",
"unicode": "U+1F511", "unicode": "U+1F511",
"translated_descriptions": { "translated_descriptions": {
"bg": "Ключ",
"ca": "Clau",
"de": "Schlüssel", "de": "Schlüssel",
"eo": "Ŝlosilo", "eo": "Ŝlosilo",
"es": "Llave", "es": "Llave",
@ -1157,6 +1253,8 @@
"description": "Hammer", "description": "Hammer",
"unicode": "U+1F528", "unicode": "U+1F528",
"translated_descriptions": { "translated_descriptions": {
"bg": "Чук",
"ca": "Martell",
"de": "Hammer", "de": "Hammer",
"eo": "Martelo", "eo": "Martelo",
"es": "Martillo", "es": "Martillo",
@ -1181,6 +1279,8 @@
"description": "Telephone", "description": "Telephone",
"unicode": "U+260EU+FE0F", "unicode": "U+260EU+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Телефон",
"ca": "Telèfon",
"de": "Telefon", "de": "Telefon",
"eo": "Telefono", "eo": "Telefono",
"es": "Telefono", "es": "Telefono",
@ -1205,6 +1305,8 @@
"description": "Flag", "description": "Flag",
"unicode": "U+1F3C1", "unicode": "U+1F3C1",
"translated_descriptions": { "translated_descriptions": {
"bg": "Флаг",
"ca": "Bandera",
"de": "Flagge", "de": "Flagge",
"eo": "Flago", "eo": "Flago",
"es": null, "es": null,
@ -1229,6 +1331,8 @@
"description": "Train", "description": "Train",
"unicode": "U+1F682", "unicode": "U+1F682",
"translated_descriptions": { "translated_descriptions": {
"bg": "Влак",
"ca": "Tren",
"de": "Zug", "de": "Zug",
"eo": "Vagonaro", "eo": "Vagonaro",
"es": "Tren", "es": "Tren",
@ -1253,6 +1357,8 @@
"description": "Bicycle", "description": "Bicycle",
"unicode": "U+1F6B2", "unicode": "U+1F6B2",
"translated_descriptions": { "translated_descriptions": {
"bg": "Колело",
"ca": "Bicicleta",
"de": "Fahrrad", "de": "Fahrrad",
"eo": "Biciklo", "eo": "Biciklo",
"es": "Bicicleta", "es": "Bicicleta",
@ -1277,6 +1383,8 @@
"description": "Aeroplane", "description": "Aeroplane",
"unicode": "U+2708U+FE0F", "unicode": "U+2708U+FE0F",
"translated_descriptions": { "translated_descriptions": {
"bg": "Самолет",
"ca": "Avió",
"de": "Flugzeug", "de": "Flugzeug",
"eo": "Aviadilo", "eo": "Aviadilo",
"es": null, "es": null,
@ -1301,6 +1409,8 @@
"description": "Rocket", "description": "Rocket",
"unicode": "U+1F680", "unicode": "U+1F680",
"translated_descriptions": { "translated_descriptions": {
"bg": "Ракета",
"ca": "Coet",
"de": "Rakete", "de": "Rakete",
"eo": "Raketo", "eo": "Raketo",
"es": null, "es": null,
@ -1325,6 +1435,8 @@
"description": "Trophy", "description": "Trophy",
"unicode": "U+1F3C6", "unicode": "U+1F3C6",
"translated_descriptions": { "translated_descriptions": {
"bg": "Трофей",
"ca": "Trofeu",
"de": "Trophäe", "de": "Trophäe",
"eo": "Trofeo", "eo": "Trofeo",
"es": null, "es": null,
@ -1349,6 +1461,8 @@
"description": "Ball", "description": "Ball",
"unicode": "U+26BD", "unicode": "U+26BD",
"translated_descriptions": { "translated_descriptions": {
"bg": "Топка",
"ca": "Pilota",
"de": "Ball", "de": "Ball",
"eo": "Pilko", "eo": "Pilko",
"es": "Bola", "es": "Bola",
@ -1373,6 +1487,8 @@
"description": "Guitar", "description": "Guitar",
"unicode": "U+1F3B8", "unicode": "U+1F3B8",
"translated_descriptions": { "translated_descriptions": {
"bg": "Китара",
"ca": "Guitarra",
"de": "Gitarre", "de": "Gitarre",
"eo": "Gitaro", "eo": "Gitaro",
"es": "Guitarra", "es": "Guitarra",
@ -1397,6 +1513,8 @@
"description": "Trumpet", "description": "Trumpet",
"unicode": "U+1F3BA", "unicode": "U+1F3BA",
"translated_descriptions": { "translated_descriptions": {
"bg": "Тромпет",
"ca": "Trompeta",
"de": "Trompete", "de": "Trompete",
"eo": "Trumpeto", "eo": "Trumpeto",
"es": "Trompeta", "es": "Trompeta",
@ -1421,6 +1539,8 @@
"description": "Bell", "description": "Bell",
"unicode": "U+1F514", "unicode": "U+1F514",
"translated_descriptions": { "translated_descriptions": {
"bg": "Звънец",
"ca": "Campana",
"de": "Glocke", "de": "Glocke",
"eo": "Sonorilo", "eo": "Sonorilo",
"es": "Campana", "es": "Campana",
@ -1445,6 +1565,8 @@
"description": "Anchor", "description": "Anchor",
"unicode": "U+2693", "unicode": "U+2693",
"translated_descriptions": { "translated_descriptions": {
"bg": "Котва",
"ca": "Àncora",
"de": "Anker", "de": "Anker",
"eo": "Ankro", "eo": "Ankro",
"es": null, "es": null,
@ -1469,6 +1591,8 @@
"description": "Headphones", "description": "Headphones",
"unicode": "U+1F3A7", "unicode": "U+1F3A7",
"translated_descriptions": { "translated_descriptions": {
"bg": "Слушалки",
"ca": "Auriculars",
"de": "Kopfhörer", "de": "Kopfhörer",
"eo": "Kapaŭdilo", "eo": "Kapaŭdilo",
"es": null, "es": null,
@ -1493,6 +1617,8 @@
"description": "Folder", "description": "Folder",
"unicode": "U+1F4C1", "unicode": "U+1F4C1",
"translated_descriptions": { "translated_descriptions": {
"bg": "Папка",
"ca": "Carpeta",
"de": "Ordner", "de": "Ordner",
"eo": "Dosierujo", "eo": "Dosierujo",
"es": null, "es": null,
@ -1517,6 +1643,8 @@
"description": "Pin", "description": "Pin",
"unicode": "U+1F4CC", "unicode": "U+1F4CC",
"translated_descriptions": { "translated_descriptions": {
"bg": "Кабърче",
"ca": "Xinxeta",
"de": "Stecknadel", "de": "Stecknadel",
"eo": "Pinglo", "eo": "Pinglo",
"es": "Alfiler", "es": "Alfiler",

@ -0,0 +1,12 @@
{
"$ref": "core/event.json",
"type": "m.room_key.withheld",
"content": {
"algorithm": "m.megolm.v1.aes-sha2",
"room_id": "!Cuyf34gef24t:localhost",
"session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
"sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
"code": "m.unverified",
"reason": "Device not verified"
}
}

@ -43,6 +43,15 @@ properties:
to the end of the list. For example, if the key is forwarded from A to B to to the end of the list. For example, if the key is forwarded from A to B to
C, this field is empty between A and B, and contains A's Curve25519 key between C, this field is empty between A and B, and contains A's Curve25519 key between
B and C. B and C.
withheld:
type: object
description: |-
Indicates that the key cannot be used to decrypt all the messages
from the session because a portion of the session was withheld as
described in `Reporting that decryption keys are withheld`_. This
object must include the ``code`` and ``reason`` properties from the
``m.room_key.withheld`` message that was received by the sender of
this message.
required: required:
- algorithm - algorithm
- room_id - room_id

@ -0,0 +1,86 @@
---
allOf:
- $ref: core-event-schema/event.yaml
description: |-
This event type is used to indicate that the sender is not sharing room keys
with the recipient. It is sent as a to-device event.
Possible values for ``code`` include:
* ``m.blacklisted``: the user/device was blacklisted.
* ``m.unverified``: the user/device was not verified, and the sender is only
sharing keys with verified users/devices.
* ``m.unauthorised``: the user/device is not allowed to have the key. For
example, this could be sent in response to a key request if the user/device
was not in the room when the original message was sent.
* ``m.unavailable``: sent in reply to a key request if the device that the
key is requested from does not have the requested key.
* ``m.no_olm``: an olm session could not be established.
In most cases, this event refers to a specific room key. The one exception to
this is when the sender is unable to establish an olm session with the
recipient. When this happens, multiple sessions will be affected. In order
to avoid filling the recipient\'s device mailbox, the sender should only send
one ``m.room_key.withheld`` message with no ``room_id`` nor ``session_id``
set. If the sender retries and fails to create an olm session again in the
future, it should not send another ``m.room_key.withheld`` message with a
``code`` of ``m.no_olm``, unless another olm session was previously
established successfully. In response to receiving an
``m.room_key.withheld`` message with a ``code`` of ``m.no_olm``, the
recipient may start an olm session with the sender and send an ``m.dummy``
message to notify the sender of the new olm session. The recipient may
assume that this ``m.room_key.withheld`` message applies to all encrypted
room messages sent before it receives the message.
properties:
content:
properties:
algorithm:
type: string
enum: ["m.megolm.v1.aes-sha2"]
description: |-
The encryption algorithm for the key that this event is about.
room_id:
type: string
description: |-
Required if ``code`` is not ``m.no_olm``. The room for the key that
this event is about.
session_id:
type: string
description: |-
Required of ``code`` is not ``m.no_olm``. The session ID of the key
that this event is aboutis for.
sender_key:
type: string
description: |-
The unpadded base64-encoded device curve25519 key of the event\'s
sender.
code:
type: string
enum:
- m.blacklisted
- m.unverified
- m.unauthorised
- m.unavailable
- m.no_olm
description: |-
A machine-readable code for why the key was not sent. Codes beginning
with `m.` are reserved for codes defined in the Matrix
specification. Custom codes must use the Java package naming
convention.
reason:
type: string
description: |-
A human-readable reason for why the key was not sent. The receiving
client should only use this string if it does not understand the
``code``.
required:
- algorithm
- sender_key
- code
type: object
type:
enum:
- m.room_key.withheld
type: string
type: object

@ -0,0 +1,297 @@
Bi-directional Key verification using QR codes
==============================================
Problem/Background
------------------
Key verification is essential in ensuring that end-to-end encrypted messages
cannot be read by unauthorized parties. Traditionally, key verification is
done by comparing long strings. To save users from the tedium of reading out
long strings, some systems allow one party to verify the other party by
scanning a QR code; by doing this twice, both parties can verify each other.
In this proposal, we present a method for both parties to verify each other by
only scanning one QR code.
Proposal
--------
When Alice and Bob meet in person to verify keys, Alice will scan a QR code
generated by Bob's device. The QR code will encode both Bob's key as well as what Bob
thinks Alice's key is. When Alice scans the QR code, she will ensure that the
keys match what is expected, in which case, she relays this information to Bob,
who can then tell his device that the keys match.
### Example flow
1. Alice and Bob meet in person, and want to verify each other's keys.
2. Alice requests a key verification through her device by sending an
`m.key.verification.request` message (see
[MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241)), with
`m.qr_code.show.v1`, `m.qr_code.scan.v1`, and `m.reciprocate.v1` listed in
`methods`, and Bob responds with a `m.key.verification.ready` message.
3. Alice's client displays a QR code that Bob is able to scan, and an option to
scan Bob's QR code.
4. Bob's client prompts Bob to verify Alice's key. The prompt includes a QR
code that Alice can scan (if the `m.key.verification.request` message listed
`m.qr_code.scan.v1`), and an option to scan Alice's QR code (if the
`m.key.verification.request` message listed `m.qr_code.show.v1`). The QR
code encodes:
- Bob's master cross-signing public key,
- what Bob thinks Alice's master cross-signing public key is,
- a random shared secret.
5. Alice scans Bob's QR code.
6. Alice's device ensures that:
- Bob's key encoded in the QR code matches the key that she already has for
Bob, and
- Alice's cross-signing key matches the cross-signing key encoded in the QR
code.
If any of these checks fail, Alice's device displays an error message
indicating that the code is incorrect, and sends a
`m.key.verification.cancel` message to Bob's device.
Otherwise, at this point:
- Alice's device has now verified Bob's key, and
- Alice's device knows that Bob has the correct key for her.
Thus for Bob to verify Alice's key, Alice needs to tell Bob that he has the
right key.
7. Alice's device displays a message saying that all is well. This message
tells Alice that she has the right key for Bob, and tells Bob that he has
the right key for Alice.
8. Alice's device sends a `m.key.verification.start` message with `method` set
to `m.reciprocate.v1` to Bob (see below). The message includes the shared
secret from the QR code. This signals to Bob's device that Alice has
scanned Bob's QR code.
This message is merely a signal for Bob's device to proceed to the next
step, and is not used for verification purposes.
9. Upon receipt of the `m.key.verification.start` message, Bob's device ensures
that the shared secret matches.
If the shared secret does not match, it should display an error message
indicating that an attack was attempted. (This does not affect Alice's
verification of Bob's keys.)
If the shared secret does match, it asks Bob to confirm that Alice
has scanned the QR code.
10. Bob sees Alice's device confirm that the key matches, and presses the button
on his device to indicate that Alice's key is verified.
Bob's verification of Alice's key hinges on Alice telling Bob the result of
her scan. Since the QR code includes what Bob thinks Alice's key is,
Alice's device can check whether Bob has the right key for her. Alice has
no motivation to lie about the result, as getting Bob to trust an incorrect
key would only affect communications between herself and Bob. Thus Alice
telling Bob that the code was scanned successfully is sufficient for Bob to
trust Alice's key, under the assumption that this communication is done
over a trusted medium (such as in-person).
11. Both devices send an `m.key.verification.done` message.
This flow allows Alice to verify Bob's key, and Bob to verify Alice's key.
Alice verifies Bob's key because she can trust the QR code that Bob displays
for her, as this is done over a trusted medium. Bob verifies Alice's key
because Alice can trust the QR code that Bob displays, and Bob can trust Alice
to tell him the result of the verification.
#### Self-verification
QR codes can also be used by a user to verify their own devices. These examples
shows Alice verifying two devices, one of them (Osborne2) having cross-signing
already set up, and the other one (Dynabook) having just logged in.
In the first example, Osborne2 scans Dynabook:
1. Alice logs into her new Dynabook and wants other users to be able to trust
it via cross-signing, and to trust other devices via cross-signing.
2. Dynabook retrieves Alice's public cross-signing key from the server, and
displays a QR code that encodes:
- Dynabook's device key,
- what it thinks Alice's master key is, and
- a random shared secret.
Note that in this case, the QR code does not include Alice's master key in a
`key_<key_id>` parameter, since Dynabook does not know whether it is trusted
or not.
3. Osborne2 scans the QR code displayed by Dynabook. At this point, Osborne2
knows Dynabook's device key and can sign it with the self-signing key and
upload the signature, and can trust Dynabook for sending secrets via SSSS.
It also knows that Dynabook has the correct cross-signing key.
4. Osborne2 tells Alice that the scan was successful, and sends the
`reciprocate` message containing the shared secret.
5. Upon receipt of the `reciprocate` message, Dynabook (after checking the
shared secret) confirms with Alice that she successfully scanned the QR
code.
6. Alice confirms.
7. Dynabook now knows that it can trust Alice's cross-signing keys that it
fetched from the server.
In the second example, Dynabook scans Osborne2:
1. Alice logs into her new Dynabook and wants other users to be able to trust
it via cross-signing, and to trust other devices via cross-signing.
2. Osborne2 notices that Dynabook is a new device. Osborne2 fetches Dynabook's
identity key and displays a QR code that encodes:
- what it thinks Dynabook's key is,
- Alice's master key, and
- a random shared secret.
3. Dynabook scans the QR code shown by Osborne2. At this point, Dynabook knows
Alice's cross-signing key, and so it can trust it to sign other devices. It
also knows that Osborne2 as the correct key for it.
4. Dynabook tells Alice that the scan is successful, and sends the
`reciprocate` message containing the shared secret.
5. Upon receipt of the `reciprocate` message, Osborne2 (after checking the
shared secret) confirms with Alice that she successfully scanned the QR
code.
6. Alice confirms.
7. Osborne2 now knows that it has the correct device key for Dynabook, and can
sign it with the self-signing key and upload the signature. Osborne2 can
also trust Dynabook for sending secrets via SSSS.
### Verification methods
This proposal defines three verification methods that can be used in
`m.key.verification.request` messages (see
[MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241)).
- `m.qr_code.show.v2`: means that the sender of the
`m.key.verification.request` message can show a QR code that the recipient
can scan. If the recipient can scan the QR code, it should allow the user to
do so. This method is never sent as part of a `m.key.verification.start`
message.
- `m.qr_code.scan.v2`: means that the sender of the
`m.key.verification.request` message can scan a QR code displayed by the
recipient. If the recipient can display a QR code, it should allow the user
to display it so that the sender can scan it. This method is never sent as
part of a `m.key.verification.start` message.
- `m.reciprocate.v1`: means that the sender can participate in a reciprocal
verification, either as initiator or responder, as described in the [Message
types](#message-types) section below.
### QR code format
The QR codes to be displayed and scanned using this format will encode binary
strings in the general form:
- the ASCII string "MATRIX"
- one byte indicating the QR code version (must be `0x02`)
- one byte indicating the QR code verification mode. May be one of the
following values:
- `0x00` verifying another user with cross-signing
- `0x01` self-verifying in which the current device does trust the master key
- `0x02` self-verifying in which the current device does not yet trust the
master key
- the event ID or `transaction_id` of the associated verification
request event, encoded as:
- two bytes in network byte order (big-endian) indicating the length in
bytes of the ID as a UTF-8 string
- the ID as a UTF-8 string
- the first key, as 32 bytes. The key to use depends on the mode field:
- if `0x00` or `0x01`, then the current user's own master cross-signing public key
- if `0x02`, then the current device's device key
- the second key, as 32 bytes. The key to use depends on the mode field:
- if `0x00`, then what the device thinks the other user's master
cross-signing key is
- if `0x01`, then what the device thinks the other device's device key is
- if `0x02`, then what the device thinks the user's master cross-signing key
is
- a random shared secret, as a byte string. It is suggested to use a secret
that is about 8 bytes long. Note: as we do not share the length of the
secret, and it is not a fixed size, clients will just use the remainder of
binary string as the shared secret.
For example, if Alice displays a QR code encoding the following binary string:
```
"MATRIX" |ver|mode| len | event ID
4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ...
| user's cross-signing key | other user's cross-signing key | shared secret
00 01 02 03 04 05 06 07 ... 10 11 12 13 14 15 16 17 ... 20 21 22 23 24 25 26 27
```
this indicates that Alice is verifying another user (say Bob), in response to
the request from event "$ABCD...", her cross-signing key is
`0001020304050607...` (which is "AAECAwQFBg..." in base64), she thinks that
Bob's cross-signing key is `1011121314151617...` (which is "EBESExQVFh..." in
base64), and the shared secret is `2021222324252627` (which is "ICEiIyQlJic" in
base64).
### Message types
#### `m.key.verification.start`
Alice's device tells Bob's device that the QR code has been scanned.
message contents:
- `method`: `m.reciprocate.v1`
- `m.relates_to`: as per [key verification framework](https://github.com/matrix-org/matrix-doc/pull/2241)
- `secret`: the shared secret from the QR code, encoded using unpadded base64
Example:
```json
{
"method": "m.reciprocate.v1",
"m.relates_to": {
"rel_type": "m.reference",
"event_id": "$event_id_of_verification_request"
},
"secret": "shared+secret"
}
```
Note that this message could be sent by either the sender or the recipient of
the `m.key.verification.request` message, depending on which user scanned the
QR code.
### Cancellation
In addition to the cancellation codes specified in [the spec for
`m.key.verification.cancel`](https://matrix.org/docs/spec/client_server/r0.5.0#m-key-verification-cancel),
the following cancellation codes may be used:
- `m.qr_code.invalid`: The QR code is invalid (e.g. it is not a URL of the
required form)
The verification can also be cancelled with the error codes:
- `m.key_mismatch`: if the QR code has keys that do not match the expected
value
- `m.user_mismatch`: if the QR code is for a different user from what was expected
Tradeoffs/Alternatives
----------------------
Other methods of verifying keys, which do not require scanning QR codes, are
needed for devices that are unable to scan QR codes. One such method is
[MSC1267](https://github.com/matrix-org/matrix-doc/issues/1267). Since the key
verification framework allows for multiple methods to be supported, clients can
allow users to use different methods depending on their capability.
Rather than embedding the keys in the QR codes directly, the two clients could
perform an exchange similar to
[MSC1267](https://github.com/matrix-org/matrix-doc/issues/1267), and encoding
the Short Authentication String code in the QR code. However, this means that
the clients must exchange several messages before they can verify each other,
which would delay showing the QR codes. This proposal is also simpler to
implement.
This proposal does not support the case of asynchronous verification, such as
printing a QR code on a business card for others to scan. That may be address
in a separate MSC.
Security Considerations
-----------------------
The security of verifying Alice's key depends on Bob not hitting the "Verified"
button (step 10 in the example flow) until after Alice's device indicates
success or failure. Users have a tendency to click on buttons without reading
what the screen says, but this is partially mitigated by the fact that it is
unlikely that Bob will be interacting with the device while Alice is scanning
and Alice's device will display the verification results immediately upon
scanning. Also, Bob's device will not display the button until it receives the
`m.key.verification.start` message that contains the shared secret from the QR
code, which means that an attacker would need to be physically present while
Alice and Bob verify. This issue can also be addressed by allowing Bob to
easily undo the verification if Alice's device displays an error.

@ -0,0 +1,51 @@
# MSC2765: Widget avatars
Currently widgets have a name and title associated with them, though no opportunity for avatars
for a favicon-like experience. This proposal introduces such a concept.
## Proposal
A new optional paramater named `avatar_url` is added to the widget definition. This parameter is
an MXC URI to an image clients can use to associate with the widget, likely alongside the `name`
and/or `title`.
Widget avatars SHOULD be legible at small sizes, such as 20x20. The MXC URI in the `avatar_url`
should be the source material to allow clients to use the `/thumbnail` API to get a size for their
use case.
Rendering avatars is optional for clients, much like how clients are not required to use the `name`
or `title` of a widget.
An example widget would be:
```json
{
"creatorUserId": "@alice:example.org",
"data": {
"custom_key": "This is a custom key",
"title": "This is a witty description for the widget"
},
"id": "20200827_WidgetExample",
"name": "My Cool Widget",
"type": "m.custom",
"url": "https://example.org/my/widget.html?roomId=$matrix_room_id",
"waitForIframeLoad": true,
"avatar_url": "mxc://example.org/abc123"
}
```
## Alternatives
We could define a whole structured system for different thumbnail sizes, though we have a thumbnail
API which can be used to request whatever size is needed by the client.
## Security considerations
Widget avatars could be non-images. Clients should use the thumbnail API to encourage error responses
from the server when a widget avatar is a non-image.
## Unstable prefix
While this MSC is not in a released version of the specification, clients should use an alternative
event type for widgets or use `org.matrix.msc2765.avatar_url` when using `m.widget` or `m.widgets`
as an event type.

@ -0,0 +1,54 @@
# MSC2774: Giving widgets their ID so they can communicate
Under the [current specification](https://github.com/matrix-org/matrix-doc/pull/2764), widgets are
able to communicate with their client host, however doing so is a bit difficult if they don't already
know their widget ID. Some widgets will be able to get their ID from another source like an
integration manager, however this is not the case for all widgets.
[MSC2762](https://github.com/matrix-org/matrix-doc/pull/2762) has a fair amount of background
information on widgets, as does the current specification linked above.
## Proposal
Currently widgets can expect a `?widgetId` query parameter sent to them in clients like Element,
however this has some issues and as such is not proposed to exist any further. One of the issues
is that the widget must retain the query string, which isn't entirely possible for some frontends
(they would instead prefer to use the fragment). It's also a privacy risk in that by being sent
through the query string, the server can be made aware of the widget ID. The widget ID doesn't
normally contain any useful information (it's an opaque string), however it's not required for
the server to function under typical usage.
The proposal is to introduce a `$matrix_widget_id` template variable for the URL, similar to the
existing `$matrix_room_id` variable. Widgets can then have their widget ID wherever they want in
the widget URL, making it easier on them to find and use.
This carries the same risks as a room ID being passed to the widget: the client can easily lie about
it, however there's no real risk involved in doing so because it's used for communication only. So
long as the client is able to identify which widget is talking to it, it doesn't really matter. It's
more of a problem if the client uses a widget ID from another widget as that could confuse the
client, however this is believed to be a bug. Clients should also be performing origin checks to
ensure the widget is talking from a sane origin and not somewhere else, like another tab or browser.
## Potential issues
This is not backwards compatible with the history of widgets so far, so clients and widgets will
need to be modified to support it. Clients which currently use the `?widgetId` parameter are
encouraged to continue supporting the parameter until sufficient adoption is reached.
## Alternatives
As mentioned, a query parameter could be used, though this has the issues previously covered. Another
solution might be to allow a single widget API action which has no widget ID solely for the purpose
of finding the widget ID, however clients are unlikely to be able to differentiate between two widgets
if this were the case.
Another solution would be to let the widget discover its widget ID by harvesting it out of the first
widget API request it sees. This can't always be relied upon (some flows require the widget to
speak first), and as the widget API becomes more capable it could become a security risk. A malicious
browser extension could spam the widget with fake requests to try and convince it to talk to it
instead of the client, thus redirecting some information to the wrong place.
## Unstable prefix
Implementations should use `$org.matrix.msc2774_widget_id` as a variable until this lands in a
released version of the specification.

@ -152,7 +152,7 @@ The complete grammar for a legal user ID is::
set. User IDs are primarily intended for use as an identifier at the protocol set. User IDs are primarily intended for use as an identifier at the protocol
level, and their use as a human-readable handle is of secondary level, and their use as a human-readable handle is of secondary
benefit. Furthermore, they are useful as a last-resort differentiator between benefit. Furthermore, they are useful as a last-resort differentiator between
users with similar display names. Allowing the full unicode character set users with similar display names. Allowing the full Unicode character set
would make very difficult for a human to distinguish two similar user IDs. The would make very difficult for a human to distinguish two similar user IDs. The
limited character set used has the advantage that even a user unfamiliar with limited character set used has the advantage that even a user unfamiliar with
the Latin alphabet should be able to distinguish similar user IDs manually, if the Latin alphabet should be able to distinguish similar user IDs manually, if
@ -190,7 +190,7 @@ history includes events with a ``sender`` which does not conform. In order to
handle these rooms successfully, clients and servers MUST accept user IDs with handle these rooms successfully, clients and servers MUST accept user IDs with
localparts from the expanded character set:: localparts from the expanded character set::
extended_user_id_char = %x21-39 / %x3B-7E ; all ascii printing chars except : extended_user_id_char = %x21-39 / %x3B-7E ; all ASCII printing chars except :
Mapping from other character sets Mapping from other character sets
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@ -251,8 +251,8 @@ risk of clashes of identifiers between different homeservers. There is no
implication that the room or event in question is still available at the implication that the room or event in question is still available at the
corresponding homeserver. corresponding homeserver.
Event IDs and Room IDs are case-sensitive. They are not meant to be human Event IDs and Room IDs are case-sensitive. They are not meant to be human-readable.
readable. They are intended to be treated as fully opaque strings by clients. They are intended to be treated as fully opaque strings by clients.
.. TODO-spec .. TODO-spec
What is the grammar for the opaque part? https://matrix.org/jira/browse/SPEC-389 What is the grammar for the opaque part? https://matrix.org/jira/browse/SPEC-389
@ -326,7 +326,7 @@ parameter is only used in the case of permalinks where an event ID is referenced
The matrix.to URI, when referenced, must always start with ``https://matrix.to/#/`` The matrix.to URI, when referenced, must always start with ``https://matrix.to/#/``
followed by the identifier. followed by the identifier.
The ``<additional arguments>`` and the preceeding question mark are optional and The ``<additional arguments>`` and the preceding question mark are optional and
only apply in certain circumstances, documented below. only apply in certain circumstances, documented below.
Clients should not rely on matrix.to URIs falling back to a web server if accessed Clients should not rely on matrix.to URIs falling back to a web server if accessed
@ -379,7 +379,7 @@ are picked is left as an implementation detail, however the current recommendati
to pick 3 unique servers based on the following criteria: to pick 3 unique servers based on the following criteria:
* The first server should be the server of the highest power level user in the room, * The first server should be the server of the highest power level user in the room,
provided they are at least power level 50. If no user meets this criteria, pick the provided they are at least power level 50. If no user meets this criterion, pick the
most popular server in the room (most joined users). The rationale for not picking most popular server in the room (most joined users). The rationale for not picking
users with power levels under 50 is that they are unlikely to be around into the users with power levels under 50 is that they are unlikely to be around into the
distant future while higher ranking users (and therefore servers) are less likely distant future while higher ranking users (and therefore servers) are less likely

@ -29,7 +29,7 @@ Canonical JSON
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
We define the canonical JSON encoding for a value to be the shortest UTF-8 JSON We define the canonical JSON encoding for a value to be the shortest UTF-8 JSON
encoding with dictionary keys lexicographically sorted by unicode codepoint. encoding with dictionary keys lexicographically sorted by Unicode codepoint.
Numbers in the JSON must be integers in the range ``[-(2**53)+1, (2**53)-1]``. Numbers in the JSON must be integers in the range ``[-(2**53)+1, (2**53)-1]``.
We pick UTF-8 as the encoding as it should be available to all platforms and We pick UTF-8 as the encoding as it should be available to all platforms and
@ -63,7 +63,7 @@ using this representation.
separators=(',',':'), separators=(',',':'),
# Sort the keys of dictionaries. # Sort the keys of dictionaries.
sort_keys=True, sort_keys=True,
# Encode the resulting unicode as UTF-8 bytes. # Encode the resulting Unicode as UTF-8 bytes.
).encode("UTF-8") ).encode("UTF-8")
Grammar Grammar

@ -28,7 +28,7 @@ victim in order to:
Threat: Resource Exhaustion Threat: Resource Exhaustion
+++++++++++++++++++++++++++ +++++++++++++++++++++++++++
An attacker could cause the victims server to exhaust a particular resource An attacker could cause the victim's server to exhaust a particular resource
(e.g. open TCP connections, CPU, memory, disk storage) (e.g. open TCP connections, CPU, memory, disk storage)
Threat: Unrecoverable Consistency Violations Threat: Unrecoverable Consistency Violations

@ -194,7 +194,7 @@ Authorization
Homeservers MUST include a query parameter named ``access_token`` containing the Homeservers MUST include a query parameter named ``access_token`` containing the
``hs_token`` from the application service's registration when making requests to ``hs_token`` from the application service's registration when making requests to
the application service. Application services MUST verify the provided ``access_token`` the application service. Application services MUST verify the provided ``access_token``
matches their known ``hs_token``, failing the request with a ``M_FORBIDDEN`` error matches their known ``hs_token``, failing the request with an ``M_FORBIDDEN`` error
if it does not match. if it does not match.
Legacy routes Legacy routes
@ -206,8 +206,8 @@ service specification now defines a version on all endpoints to be more compatib
with the rest of the Matrix specification and the future. with the rest of the Matrix specification and the future.
Homeservers should attempt to use the specified endpoints first when communicating Homeservers should attempt to use the specified endpoints first when communicating
with application services. However, if the application service receives an http status with application services. However, if the application service receives an HTTP status
code that does not indicate success (ie: 404, 500, 501, etc) then the homeserver code that does not indicate success (i.e.: 404, 500, 501, etc) then the homeserver
should fall back to the older endpoints for the application service. should fall back to the older endpoints for the application service.
The older endpoints have the exact same request body and response format, they The older endpoints have the exact same request body and response format, they

@ -186,7 +186,7 @@ Other error codes the client might encounter are:
permits, for example, email addresses from a particular domain. permits, for example, email addresses from a particular domain.
:``M_SERVER_NOT_TRUSTED``: :``M_SERVER_NOT_TRUSTED``:
The client's request used a third party server, eg. identity server, that this server does not trust. The client's request used a third party server, e.g. identity server, that this server does not trust.
:``M_UNSUPPORTED_ROOM_VERSION``: :``M_UNSUPPORTED_ROOM_VERSION``:
The client's request to create a room used a room version that the server does not support. The client's request to create a room used a room version that the server does not support.
@ -228,8 +228,8 @@ Other error codes the client might encounter are:
may reach a resource limit if it starts using too much memory or disk space. The may reach a resource limit if it starts using too much memory or disk space. The
error MUST have an ``admin_contact`` field to provide the user receiving the error error MUST have an ``admin_contact`` field to provide the user receiving the error
a place to reach out to. Typically, this error will appear on routes which attempt a place to reach out to. Typically, this error will appear on routes which attempt
to modify state (eg: sending messages, account data, etc) and not routes which only to modify state (e.g.: sending messages, account data, etc) and not routes which only
read state (eg: ``/sync``, get account data, etc). read state (e.g.: ``/sync``, get account data, etc).
:``M_CANNOT_LEAVE_SERVER_NOTICE_ROOM``: :``M_CANNOT_LEAVE_SERVER_NOTICE_ROOM``:
The user is unable to reject an invite to join the server notices room. See the The user is unable to reject an invite to join the server notices room. See the
@ -266,8 +266,8 @@ to pre-flight requests and supply Cross-Origin Resource Sharing (CORS) headers o
all requests. all requests.
Servers MUST expect that clients will approach them with ``OPTIONS`` requests, Servers MUST expect that clients will approach them with ``OPTIONS`` requests,
allowing clients to discover the CORS headers. All endpoints in this specification s allowing clients to discover the CORS headers. All endpoints in this specification
upport the ``OPTIONS`` method, however the server MUST NOT perform any logic defined support the ``OPTIONS`` method, however the server MUST NOT perform any logic defined
for the endpoints when approached with an ``OPTIONS`` request. for the endpoints when approached with an ``OPTIONS`` request.
When a client approaches the server with a request, the server should respond with When a client approaches the server with a request, the server should respond with
@ -438,7 +438,7 @@ homeserver may provide many different ways of authenticating, such as
user/password auth, login via a single-sign-on server (SSO), etc. This user/password auth, login via a single-sign-on server (SSO), etc. This
specification does not define how homeservers should authorise their users but specification does not define how homeservers should authorise their users but
instead defines the standard interface which implementations should follow so instead defines the standard interface which implementations should follow so
that ANY client can login to ANY homeserver. that ANY client can log in to ANY homeserver.
The process takes the form of one or more 'stages'. At each stage the client The process takes the form of one or more 'stages'. At each stage the client
submits a set of data for a given authentication type and awaits a response submits a set of data for a given authentication type and awaits a response
@ -707,7 +707,7 @@ For example, to authenticate using the user's Matrix ID, clients would submit:
} }
Alternatively reply using a 3PID bound to the user's account on the homeserver Alternatively reply using a 3PID bound to the user's account on the homeserver
using the |/account/3pid|_ API rather then giving the ``user`` explicitly as using the |/account/3pid|_ API rather than giving the ``user`` explicitly as
follows: follows:
.. code:: json .. code:: json
@ -827,7 +827,7 @@ Dummy Auth
Dummy authentication always succeeds and requires no extra parameters. Its Dummy authentication always succeeds and requires no extra parameters. Its
purpose is to allow servers to not require any form of User-Interactive purpose is to allow servers to not require any form of User-Interactive
Authentication to perform a request. It can also be used to differentiate Authentication to perform a request. It can also be used to differentiate
flows where otherwise one flow would be a subset of another flow. eg. if flows where otherwise one flow would be a subset of another flow. e.g. if
a server offers flows ``m.login.recaptcha`` and ``m.login.recaptcha, a server offers flows ``m.login.recaptcha`` and ``m.login.recaptcha,
m.login.email.identity`` and the client completes the recaptcha stage first, m.login.email.identity`` and the client completes the recaptcha stage first,
the auth would succeed with the former flow, even if the client was intending the auth would succeed with the former flow, even if the client was intending
@ -878,7 +878,7 @@ to be defined in an embedded browser, or to use the HTML5 `cross-document
messaging <https://www.w3.org/TR/webmessaging/#web-messaging>`_ API, to receive messaging <https://www.w3.org/TR/webmessaging/#web-messaging>`_ API, to receive
a notification that the authentication stage has been completed. a notification that the authentication stage has been completed.
Once a client receives the notificaton that the authentication stage has been Once a client receives the notification that the authentication stage has been
completed, it should resubmit the request with an auth dict with just the completed, it should resubmit the request with an auth dict with just the
session ID: session ID:
@ -891,19 +891,19 @@ session ID:
Example Example
<<<<<<< <<<<<<<
A client webapp might use the following javascript to open a popup window which will A client webapp might use the following JavaScript to open a popup window which will
handle unknown login types: handle unknown login types:
.. code:: javascript .. code:: javascript
/** /**
* Arguments: * Arguments:
* homeserverUrl: the base url of the homeserver (eg "https://matrix.org") * homeserverUrl: the base url of the homeserver (e.g. "https://matrix.org")
* *
* apiEndpoint: the API endpoint being used (eg * apiEndpoint: the API endpoint being used (e.g.
* "/_matrix/client/%CLIENT_MAJOR_VERSION%/account/password") * "/_matrix/client/%CLIENT_MAJOR_VERSION%/account/password")
* *
* loginType: the loginType being attempted (eg "m.login.recaptcha") * loginType: the loginType being attempted (e.g. "m.login.recaptcha")
* *
* sessionID: the session ID given by the homeserver in earlier requests * sessionID: the session ID given by the homeserver in earlier requests
* *
@ -930,7 +930,7 @@ handle unknown login types:
}; };
request({ request({
method:'POST', url:apiEndpint, json:requestBody, method:'POST', url:apiEndpoint, json:requestBody,
}, onComplete); }, onComplete);
}; };
@ -1044,7 +1044,7 @@ request as follows:
} }
Alternatively, a client can use a 3PID bound to the user's account on the Alternatively, a client can use a 3PID bound to the user's account on the
homeserver using the |/account/3pid|_ API rather then giving the ``user`` homeserver using the |/account/3pid|_ API rather than giving the ``user``
explicitly, as follows: explicitly, as follows:
.. code:: json .. code:: json
@ -1130,7 +1130,7 @@ can be proxied (bound) to the identity server in many cases.
This section deals with two terms: "add" and "bind". Where "add" (or "remove") This section deals with two terms: "add" and "bind". Where "add" (or "remove")
is used, it is speaking about an identifier that was not bound to an identity is used, it is speaking about an identifier that was not bound to an identity
server. As a result, "bind" (or "unbind") references an identifier that is found server. As a result, "bind" (or "unbind") references an identifier that is found
in an identity server. Note that an identifer can be added and bound at the same in an identity server. Note that an identifier can be added and bound at the same
time, depending on context. time, depending on context.
{{administrative_contact_cs_http_api}} {{administrative_contact_cs_http_api}}
@ -1745,7 +1745,7 @@ same way a server does.
except those protected by the redaction algorithm. For example, except those protected by the redaction algorithm. For example,
a redacted ``join`` event will still result in the user being considered joined. a redacted ``join`` event will still result in the user being considered joined.
Similarly, a redacted topic does not necessarily cause the topic to revert to Similarly, a redacted topic does not necessarily cause the topic to revert to
what is was prior to the event - it causes the topic to be removed from the room. what it was prior to the event - it causes the topic to be removed from the room.
Events Events
@ -1977,9 +1977,9 @@ many places of a client's display, changes to these fields cause an automatic
propagation event to occur, informing likely-interested parties of the new propagation event to occur, informing likely-interested parties of the new
values. This change is conveyed using two separate mechanisms: values. This change is conveyed using two separate mechanisms:
- a ``m.room.member`` event (with a ``join`` membership) is sent to every room - an ``m.room.member`` event (with a ``join`` membership) is sent to every room
the user is a member of, to update the ``displayname`` and ``avatar_url``. the user is a member of, to update the ``displayname`` and ``avatar_url``.
- a ``m.presence`` presence status update is sent, again containing the new - an ``m.presence`` presence status update is sent, again containing the new
values of the ``displayname`` and ``avatar_url`` keys, in addition to the values of the ``displayname`` and ``avatar_url`` keys, in addition to the
required ``presence`` key containing the current presence state of the user. required ``presence`` key containing the current presence state of the user.

@ -225,7 +225,7 @@ Terms of service
Identity Servers are encouraged to have terms of service (or similar policies) to Identity Servers are encouraged to have terms of service (or similar policies) to
ensure that users have agreed to their data being processed by the server. To facilitate ensure that users have agreed to their data being processed by the server. To facilitate
this, an identity server can respond to almost any authenticated API endpoint with a this, an identity server can respond to almost any authenticated API endpoint with an
HTTP 403 and the error code ``M_TERMS_NOT_SIGNED``. The error code is used to indicate HTTP 403 and the error code ``M_TERMS_NOT_SIGNED``. The error code is used to indicate
that the user must accept new terms of service before being able to continue. that the user must accept new terms of service before being able to continue.
@ -421,7 +421,7 @@ i.e. I can claim that any email address I own is associated with
Sessions are time-limited; a session is considered to have been modified when Sessions are time-limited; a session is considered to have been modified when
it was created, and then when a validation is performed within it. A session can it was created, and then when a validation is performed within it. A session can
only be checked for validation, and validation can only be performed within a only be checked for validation, and validation can only be performed within a
session, within a 24 hour period since its most recent modification. Any session, within a 24-hour period since its most recent modification. Any
attempts to perform these actions after the expiry will be rejected, and a new attempts to perform these actions after the expiry will be rejected, and a new
session should be created and used instead. session should be created and used instead.

@ -431,7 +431,7 @@ Profiles
~~~~~~~~ ~~~~~~~~
Users may publish arbitrary key/value data associated with their account - such Users may publish arbitrary key/value data associated with their account - such
as a human readable display name, a profile photo URL, contact information as a human-readable display name, a profile photo URL, contact information
(email address, phone numbers, website URLs etc). (email address, phone numbers, website URLs etc).
.. TODO .. TODO

@ -83,7 +83,7 @@ Base64`_. Example:
"JGLn/yafz74HB2AbPLYJWIVGnKAtqECOBf11yyXac2Y" "JGLn/yafz74HB2AbPLYJWIVGnKAtqECOBf11yyXac2Y"
The name ``signed_curve25519`` also corresponds to the Curve25519 algorithm, The name ``signed_curve25519`` also corresponds to the Curve25519 algorithm,
but a key using this algorithm is represented by an object with a the following but a key using this algorithm is represented by an object with the following
properties: properties:
``KeyObject`` ``KeyObject``
@ -431,7 +431,7 @@ Device verification may reach one of several conclusions. For example:
Key verification framework Key verification framework
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
Verifying keys manually by reading out the Ed25519 key is not very user friendly, Verifying keys manually by reading out the Ed25519 key is not very user-friendly,
and can lead to errors. In order to help mitigate errors, and to make the process and can lead to errors. In order to help mitigate errors, and to make the process
easier for users, some verification methods are supported by the specification. easier for users, some verification methods are supported by the specification.
The methods all use a common framework for negotiating the key verification. The methods all use a common framework for negotiating the key verification.
@ -443,7 +443,7 @@ allows Bob to reject the request on one device, and have it apply to all of his
devices. Similarly, it allows Bob to process the verification on one device without devices. Similarly, it allows Bob to process the verification on one device without
having to involve all of his devices. having to involve all of his devices.
When Bob's device receives a ``m.key.verification.request``, it should prompt Bob When Bob's device receives an ``m.key.verification.request``, it should prompt Bob
to verify keys with Alice using one of the supported methods in the request. If to verify keys with Alice using one of the supported methods in the request. If
Bob's device does not understand any of the methods, it should not cancel the request Bob's device does not understand any of the methods, it should not cancel the request
as one of his other devices may support the request. Instead, Bob's device should as one of his other devices may support the request. Instead, Bob's device should
@ -454,17 +454,17 @@ minutes after Bob's client receives the message, whichever comes first, if Bob
does not interact with the prompt. The prompt should additionally be hidden if does not interact with the prompt. The prompt should additionally be hidden if
an appropriate ``m.key.verification.cancel`` message is received. an appropriate ``m.key.verification.cancel`` message is received.
If Bob rejects the request, Bob's client must send a ``m.key.verification.cancel`` If Bob rejects the request, Bob's client must send an ``m.key.verification.cancel``
message to Alice's device. Upon receipt, Alice's device should tell her that Bob message to Alice's device. Upon receipt, Alice's device should tell her that Bob
does not want to verify her device and send ``m.key.verification.cancel`` messages does not want to verify her device and send ``m.key.verification.cancel`` messages
to all of Bob's devices to notify them that the request was rejected. to all of Bob's devices to notify them that the request was rejected.
If Bob accepts the request, Bob's device starts the key verification process by If Bob accepts the request, Bob's device starts the key verification process by
sending a ``m.key.verification.start`` message to Alice's device. Upon receipt sending an ``m.key.verification.start`` message to Alice's device. Upon receipt
of this message, Alice's device should send a ``m.key.verification.cancel`` message of this message, Alice's device should send an ``m.key.verification.cancel`` message
to all of Bob's other devices to indicate the process has been started. The start to all of Bob's other devices to indicate the process has been started. The start
message must use the same ``transaction_id`` from the original key verification message must use the same ``transaction_id`` from the original key verification
request if it is in response to the request. The start message can be sent indepdently request if it is in response to the request. The start message can be sent independently
of any request. of any request.
Individual verification methods may add additional steps, events, and properties to Individual verification methods may add additional steps, events, and properties to
@ -473,7 +473,7 @@ be under the ``m.key.verification`` namespace and any other event types must be
according to the Java package naming convention. according to the Java package naming convention.
Any of Alice's or Bob's devices can cancel the key verification request or process Any of Alice's or Bob's devices can cancel the key verification request or process
at any time with a ``m.key.verification.cancel`` message to all applicable devices. at any time with an ``m.key.verification.cancel`` message to all applicable devices.
This framework yields the following handshake, assuming both Alice and Bob each have This framework yields the following handshake, assuming both Alice and Bob each have
2 devices, Bob's first device accepts the key verification request, and Alice's second 2 devices, Bob's first device accepts the key verification request, and Alice's second
@ -516,7 +516,7 @@ Short Authentication String (SAS) verification
SAS verification is a user-friendly key verification process built off the common SAS verification is a user-friendly key verification process built off the common
framework outlined above. SAS verification is intended to be a highly interactive framework outlined above. SAS verification is intended to be a highly interactive
process for users, and as such exposes verfiication methods which are easier for process for users, and as such exposes verification methods which are easier for
users to use. users to use.
The verification process is heavily inspired by Phil Zimmermann's ZRTP key agreement The verification process is heavily inspired by Phil Zimmermann's ZRTP key agreement
@ -553,17 +553,17 @@ The process between Alice and Bob verifying each other would be:
#. Alice and Bob communicate which devices they'd like to verify with each other. #. Alice and Bob communicate which devices they'd like to verify with each other.
#. Alice selects Bob's device from the device list and begins verification. #. Alice selects Bob's device from the device list and begins verification.
#. Alice's client ensures it has a copy of Bob's device key. #. Alice's client ensures it has a copy of Bob's device key.
#. Alice's device sends Bob's device a ``m.key.verification.start`` message. #. Alice's device sends Bob's device an ``m.key.verification.start`` message.
#. Bob's device receives the message and selects a key agreement protocol, hash #. Bob's device receives the message and selects a key agreement protocol, hash
algorithm, message authentication code, and SAS method supported by Alice's algorithm, message authentication code, and SAS method supported by Alice's
device. device.
#. Bob's device ensures it has a copy of Alice's device key. #. Bob's device ensures it has a copy of Alice's device key.
#. Bob's device creates an ephemeral Curve25519 key pair (|BobCurve25519|), and #. Bob's device creates an ephemeral Curve25519 key pair (|BobCurve25519|), and
calculates the hash (using the chosen algorithm) of the public key |BobPublicKey|. calculates the hash (using the chosen algorithm) of the public key |BobPublicKey|.
#. Bob's device replies to Alice's device with a ``m.key.verification.accept`` message. #. Bob's device replies to Alice's device with an ``m.key.verification.accept`` message.
#. Alice's device receives Bob's message and stores the commitment hash for later use. #. Alice's device receives Bob's message and stores the commitment hash for later use.
#. Alice's device creates an ephemeral Curve25519 key pair (|AliceCurve25519|) and #. Alice's device creates an ephemeral Curve25519 key pair (|AliceCurve25519|) and
replies to Bob's device with a ``m.key.verification.key``, sending only the public replies to Bob's device with an ``m.key.verification.key``, sending only the public
key |AlicePublicKey|. key |AlicePublicKey|.
#. Bob's device receives Alice's message and replies with its own ``m.key.verification.key`` #. Bob's device receives Alice's message and replies with its own ``m.key.verification.key``
message containing its public key |BobPublicKey|. message containing its public key |BobPublicKey|.
@ -578,11 +578,11 @@ The process between Alice and Bob verifying each other would be:
#. Alice and Bob compare the strings shown by their devices, and tell their devices if #. Alice and Bob compare the strings shown by their devices, and tell their devices if
they match or not. they match or not.
#. Assuming they match, Alice and Bob's devices calculate the HMAC of their own device keys #. Assuming they match, Alice and Bob's devices calculate the HMAC of their own device keys
and a comma-separated sorted list of of the key IDs that they wish the other user and a comma-separated sorted list of the key IDs that they wish the other user
to verify, using SHA-256 as the hash function. HMAC is defined in `RFC 2104 <https://tools.ietf.org/html/rfc2104>`_. to verify, using SHA-256 as the hash function. HMAC is defined in `RFC 2104 <https://tools.ietf.org/html/rfc2104>`_.
The key for the HMAC is different for each item and is calculated by generating The key for the HMAC is different for each item and is calculated by generating
32 bytes (256 bits) using `the key verification HKDF <#sas-hkdf>`_. 32 bytes (256 bits) using `the key verification HKDF <#sas-hkdf>`_.
#. Alice's device sends Bob's device a ``m.key.verification.mac`` message containing the #. Alice's device sends Bob's device an ``m.key.verification.mac`` message containing the
MAC of Alice's device keys and the MAC of her key IDs to be verified. Bob's device does MAC of Alice's device keys and the MAC of her key IDs to be verified. Bob's device does
the same for Bob's device keys and key IDs concurrently with Alice. the same for Bob's device keys and key IDs concurrently with Alice.
#. When the other device receives the ``m.key.verification.mac`` message, the device #. When the other device receives the ``m.key.verification.mac`` message, the device
@ -619,20 +619,20 @@ The wire protocol looks like the following between Alice and Bob's devices::
Error and exception handling Error and exception handling
<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<<<<
At any point the interactive verfication can go wrong. The following describes what At any point the interactive verification can go wrong. The following describes what
to do when an error happens: to do when an error happens:
* Alice or Bob can cancel the verification at any time. A ``m.key.verification.cancel`` * Alice or Bob can cancel the verification at any time. An ``m.key.verification.cancel``
message must be sent to signify the cancellation. message must be sent to signify the cancellation.
* The verification can time out. Clients should time out a verification that does not * The verification can time out. Clients should time out a verification that does not
complete within 10 minutes. Additionally, clients should expire a ``transaction_id`` complete within 10 minutes. Additionally, clients should expire a ``transaction_id``
which goes unused for 10 minutes after having last sent/received it. The client should which goes unused for 10 minutes after having last sent/received it. The client should
inform the user that the verification timed out, and send an appropriate inform the user that the verification timed out, and send an appropriate
``m.key.verification.cancel`` message to the other device. ``m.key.verification.cancel`` message to the other device.
* When the same device attempts to intiate multiple verification attempts, the receipient * When the same device attempts to initiate multiple verification attempts, the recipient
should cancel all attempts with that device. should cancel all attempts with that device.
* When a device receives an unknown ``transaction_id``, it should send an appropriate * When a device receives an unknown ``transaction_id``, it should send an appropriate
``m.key.verfication.cancel`` message to the other device indicating as such. This ``m.key.verification.cancel`` message to the other device indicating as such. This
does not apply for inbound ``m.key.verification.start`` or ``m.key.verification.cancel`` does not apply for inbound ``m.key.verification.start`` or ``m.key.verification.cancel``
messages. messages.
* If the two devices do not share a common key share, hash, HMAC, or SAS method then * If the two devices do not share a common key share, hash, HMAC, or SAS method then
@ -792,14 +792,19 @@ Key requests
When a device is missing keys to decrypt messages, it can request the keys by When a device is missing keys to decrypt messages, it can request the keys by
sending `m.room_key_request`_ to-device messages to other devices with sending `m.room_key_request`_ to-device messages to other devices with
``action`` set to ``request``. If a device wishes to share the keys with that ``action`` set to ``request``.
device, it can forward the keys to the first device by sending an encrypted
`m.forwarded_room_key`_ to-device message. The first device should then send an If a device wishes to share the keys with that device, it can forward the keys
`m.room_key_request`_ to-device message with ``action`` set to to the first device by sending an encrypted `m.forwarded_room_key`_ to-device
``request_cancellation`` to the other devices that it had originally sent the key message. The first device should then send an `m.room_key_request`_ to-device
request to; a device that receives a ``request_cancellation`` should disregard any message with ``action`` set to ``request_cancellation`` to the other devices
previously-received ``request`` message with the same ``request_id`` and that it had originally sent the key request to; a device that receives a
``requesting_device_id``. ``request_cancellation`` should disregard any previously-received ``request``
message with the same ``request_id`` and ``requesting_device_id``.
If a device does not wish to share keys with that device, it can indicate this
by sending an `m.room_key.withheld`_ to-device message, as described in
`Reporting that decryption keys are withheld`_.
.. NOTE:: .. NOTE::
@ -1164,7 +1169,7 @@ session has become corrupted and create a new one to replace it.
to decrypt it successfully. Olm does not have a way to recover from the failure, to decrypt it successfully. Olm does not have a way to recover from the failure,
making this session replacement process required. making this session replacement process required.
To establish a new session, the client sends a `m.dummy <#m-dummy>`_ to-device event To establish a new session, the client sends an `m.dummy <#m-dummy>`_ to-device event
to the other party to notify them of the new session details. to the other party to notify them of the new session details.
Clients should rate-limit the number of sessions it creates per device that it receives Clients should rate-limit the number of sessions it creates per device that it receives
@ -1227,13 +1232,13 @@ who sent the message. The same reasoning applies, but the sender ed25519 key has
inferred from the ``keys.ed25519`` property of the event which established the Megolm inferred from the ``keys.ed25519`` property of the event which established the Megolm
session. session.
In order to enable end-to-end encryption in a room, clients can send a In order to enable end-to-end encryption in a room, clients can send an
``m.room.encryption`` state event specifying ``m.megolm.v1.aes-sha2`` as its ``m.room.encryption`` state event specifying ``m.megolm.v1.aes-sha2`` as its
``algorithm`` property. ``algorithm`` property.
When creating a Megolm session in a room, clients must share the corresponding session When creating a Megolm session in a room, clients must share the corresponding session
key using Olm with the intended recipients, so that they can decrypt future messages key using Olm with the intended recipients, so that they can decrypt future messages
encrypted using this session. A ``m.room_key`` event is used to do this. Clients encrypted using this session. An ``m.room_key`` event is used to do this. Clients
must also handle ``m.room_key`` events sent by other devices in order to decrypt their must also handle ``m.room_key`` events sent by other devices in order to decrypt their
messages. messages.
@ -1270,7 +1275,7 @@ Extensions to /sync
This module adds an optional ``device_lists`` property to the |/sync|_ This module adds an optional ``device_lists`` property to the |/sync|_
response, as specified below. The server need only populate this property for response, as specified below. The server need only populate this property for
an incremental ``/sync`` (ie, one where the ``since`` parameter was an incremental ``/sync`` (i.e., one where the ``since`` parameter was
specified). The client is expected to use |/keys/query|_ or |/keys/changes|_ specified). The client is expected to use |/keys/query|_ or |/keys/changes|_
for the equivalent functionality after an initial sync, as documented in for the equivalent functionality after an initial sync, as documented in
`Tracking the device list for a user`_. `Tracking the device list for a user`_.
@ -1333,6 +1338,32 @@ Example response:
} }
} }
Reporting that decryption keys are withheld
-------------------------------------------
When sending an encrypted event to a room, a client can optionally signal to
other devices in that room that it is not sending them the keys needed to
decrypt the event. In this way, the receiving client can indicate to the user
why it cannot decrypt the event, rather than just showing a generic error
message.
In the same way, when one device requests keys from another using `Key
requests`_, the device from which the key is being requested may want to tell
the requester that it is purposely not sharing the key.
If Alice withholds a megolm session from Bob for some messages in a room, and
then later on decides to allow Bob to decrypt later messages, she can send Bob
the megolm session, ratcheted up to the point at which she allows Bob to
decrypt the messages. If Bob logs into a new device and uses key sharing to
obtain the decryption keys, the new device will be sent the megolm sessions
that have been ratcheted up. Bob's old device can include the reason that the
session was initially not shared by including a ``withheld`` property in the
``m.forwarded_room_key`` message that is an object with the ``code`` and
``reason`` properties from the ``m.room_key.withheld`` message.
{{m_room_key_withheld_event}}
.. References .. References
.. _ed25519: http://ed25519.cr.yp.to/ .. _ed25519: http://ed25519.cr.yp.to/

@ -121,7 +121,7 @@ the tag and its contents and therefore may wish to exclude the tag entirely.
.. Note:: .. Note::
A future iteration of the specification will support more powerful and extensible A future iteration of the specification will support more powerful and extensible
message formatting options, such as the proposal `MSC1225 <https://github.com/matrix-org/matrix-doc/issues/1225>`_. message formatting options, such as the proposal `MSC1767 <https://github.com/matrix-org/matrix-doc/pull/1767>`_.
{{msgtype_events}} {{msgtype_events}}

@ -77,7 +77,7 @@ is as follows:
Subscribing to policy lists Subscribing to policy lists
--------------------------- ---------------------------
This is deliberatly left as an implementation detail. For implementations using the This is deliberately left as an implementation detail. For implementations using the
Client-Server API, this could be as easy as joining or peeking the room. Joining or peeking Client-Server API, this could be as easy as joining or peeking the room. Joining or peeking
is not required, however: an implementation could poll for updates or use a different is not required, however: an implementation could poll for updates or use a different
technique for receiving updates to the policy's rules. technique for receiving updates to the policy's rules.
@ -108,7 +108,7 @@ or room alias - the subscriber is responsible for resolving the alias to a room
Client behaviour Client behaviour
---------------- ----------------
As described above, the client behaviour is deliberatly left undefined. As described above, the client behaviour is deliberately left undefined.
Server behaviour Server behaviour
---------------- ----------------

@ -132,7 +132,7 @@ As a worked example:
1. Video conferencing is clearly a feature which would benefit 1. Video conferencing is clearly a feature which would benefit
the whole ecosystem, and so the spec should find a way to make it happen. the whole ecosystem, and so the spec should find a way to make it happen.
2. Video conferencing can be achieved by widgets without requiring any 2. Video conferencing can be achieved by widgets without requiring any
compulsory changes to changes to clients nor servers to work, and so could be compulsory changes to clients nor servers to work, and so could be
omitted from the spec. omitted from the spec.
3. A better experience could be achieved by embedding Jitsi natively into clients 3. A better experience could be achieved by embedding Jitsi natively into clients
rather than using a widget... rather than using a widget...
@ -145,10 +145,10 @@ for doing so), or to keep it as a widget-based approach (optionally with widget
extensions specific for more deeply integrating video conferencing use cases). extensions specific for more deeply integrating video conferencing use cases).
As an alternative example: it's very unlikely that "how to visualise Magnetic As an alternative example: it's very unlikely that "how to visualise Magnetic
Resonsance Imaging data over Matrix" would ever be added to the Matrix spec Resonance Imaging data over Matrix" would ever be added to the Matrix spec
(other than perhaps a custom event type in a wider standardised Matrix event (other than perhaps a custom event type in a wider standardised Matrix event
registry) given that the spec's existing primitives of file transfer and registry) given that the spec's existing primitives of file transfer and
extensible events (MSC1767) give excellent tools for transfering and extensible events (MSC1767) give excellent tools for transferring and
visualising arbitrary rich data. visualising arbitrary rich data.
Supporting public search engines are likely to not require custom spec features Supporting public search engines are likely to not require custom spec features
@ -168,7 +168,7 @@ Process
The process for submitting a Matrix Spec Change (MSC) Proposal in detail is as The process for submitting a Matrix Spec Change (MSC) Proposal in detail is as
follows: follows:
- Create a first draft of your proposal using `GitHub-flavored markdown - Create a first draft of your proposal using `GitHub-flavored Markdown
<https://help.github.com/articles/basic-writing-and-formatting-syntax/>`_ <https://help.github.com/articles/basic-writing-and-formatting-syntax/>`_
- In the document, clearly state the problem being solved, and the possible - In the document, clearly state the problem being solved, and the possible
@ -190,7 +190,7 @@ follows:
- The proposal must live in the ``proposals/`` directory with a filename that - The proposal must live in the ``proposals/`` directory with a filename that
follows the format ``1234-my-new-proposal.md`` where ``1234`` is the MSC follows the format ``1234-my-new-proposal.md`` where ``1234`` is the MSC
ID. ID.
- Your PR description must include a link to the rendered markdown document - Your PR description must include a link to the rendered Markdown document
and a summary of the proposal. and a summary of the proposal.
- It is often very helpful to link any related MSCs or `matrix-doc issues - It is often very helpful to link any related MSCs or `matrix-doc issues
<https://github.com/matrix-org/matrix-doc/issues>`_ to give context <https://github.com/matrix-org/matrix-doc/issues>`_ to give context
@ -209,10 +209,10 @@ follows:
If preferred, an alternative room can be created and advertised in If preferred, an alternative room can be created and advertised in
#matrix-spec:matrix.org. Please also link to the room in your PR #matrix-spec:matrix.org. Please also link to the room in your PR
description. description.
- For additional discussion areas, know that that #matrix-dev:matrix.org is - For additional discussion areas, know that #matrix-dev:matrix.org is
for developers using existing Matrix APIs, #matrix:matrix.org is for users for developers using existing Matrix APIs, #matrix:matrix.org is for users
trying to run Matrix apps (clients & servers) and trying to run Matrix apps (clients & servers) and
#matrix-architecture:matrix.org is for cross-cutting discussion of matrix's #matrix-architecture:matrix.org is for cross-cutting discussion of Matrix's
architectural design. architectural design.
- The point of the spec proposal process is to be collaborative rather than - The point of the spec proposal process is to be collaborative rather than
competitive, and to try to solve the problem in question with the optimal competitive, and to try to solve the problem in question with the optimal
@ -239,7 +239,7 @@ follows:
the current state of the discussion, along with reasoning for its occurrence. the current state of the discussion, along with reasoning for its occurrence.
- A concern can be raised by a Spec Core Team member at any time, which will block - A concern can be raised by a Spec Core Team member at any time, which will block
an FCP from beginning. An FCP will only begin when 75% of the members of the an FCP from beginning. An FCP will only begin when 75% of the members of the
Spec Core Team team agree on its outcome, and all existing concerns have been Spec Core Team agree on its outcome, and all existing concerns have been
resolved. resolved.
- The FCP will then begin and last for 5 days, giving anyone else some time to - The FCP will then begin and last for 5 days, giving anyone else some time to
speak up before it concludes. On its conclusion, the disposition of the FCP speak up before it concludes. On its conclusion, the disposition of the FCP
@ -332,7 +332,7 @@ Proposal Drafting and Feedback N/A A proposal docum
Proposal In Review proposal-in-review A proposal document which is now ready and waiting for review by the Spec Core Team and community Proposal In Review proposal-in-review A proposal document which is now ready and waiting for review by the Spec Core Team and community
Proposed Final Comment Period proposed-final-comment-period Currently awaiting signoff of a 75% majority of team members in order to enter the final comment period Proposed Final Comment Period proposed-final-comment-period Currently awaiting signoff of a 75% majority of team members in order to enter the final comment period
Final Comment Period final-comment-period A proposal document which has reached final comment period either for merge, closure or postponement Final Comment Period final-comment-period A proposal document which has reached final comment period either for merge, closure or postponement
Final Commment Period Complete finished-final-comment-period The final comment period has been completed. Waiting for a demonstration implementation Final Comment Period Complete finished-final-comment-period The final comment period has been completed. Waiting for a demonstration implementation
Spec PR Missing spec-pr-missing The proposal has been agreed, and proven with a demonstration implementation. Waiting for a PR against the Spec Spec PR Missing spec-pr-missing The proposal has been agreed, and proven with a demonstration implementation. Waiting for a PR against the Spec
Spec PR In Review spec-pr-in-review The spec PR has been written, and is currently under review Spec PR In Review spec-pr-in-review The spec PR has been written, and is currently under review
Spec PR Merged merged A proposal with a sufficient working implementation and whose Spec PR has been merged! Spec PR Merged merged A proposal with a sufficient working implementation and whose Spec PR has been merged!
@ -352,7 +352,7 @@ an effort to pull MSCs out of that category when possible.
The current categories are: The current categories are:
============ ================= ====================================== ============ ================= ======================================
Name Github Label Description Name GitHub Label Description
============ ================= ====================================== ============ ================= ======================================
Core kind:core Important for the protocol's success. Core kind:core Important for the protocol's success.
Feature kind:feature Nice to have additions to the spec. Feature kind:feature Nice to have additions to the spec.
@ -379,11 +379,11 @@ As part of the proposal process the spec core team will require evidence of the
working in order for it to move into FCP. This can usually be a branch/pull request working in order for it to move into FCP. This can usually be a branch/pull request
to whichever implementation of choice that proves the MSC works in practice, though to whichever implementation of choice that proves the MSC works in practice, though
in some cases the MSC itself will be small enough to be considered proven. Where it's in some cases the MSC itself will be small enough to be considered proven. Where it's
unclear if a MSC will require an implementation proof, ask in `#matrix-spec:matrix.org unclear if an MSC will require an implementation proof, ask in `#matrix-spec:matrix.org
<https://matrix.to/#/#matrix-spec:matrix.org>`_. <https://matrix.to/#/#matrix-spec:matrix.org>`_.
Early release of a MSC/idea Early release of an MSC/idea
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To help facilitate early releases of software dependent on a spec release, implementations To help facilitate early releases of software dependent on a spec release, implementations
are required to use the following process to ensure that the official Matrix namespace are required to use the following process to ensure that the official Matrix namespace
@ -447,7 +447,7 @@ is not cluttered with development or testing data.
.. Note:: .. Note::
MSCs MUST still describe what the stable endpoints/feature looks like with a note MSCs MUST still describe what the stable endpoints/feature looks like with a note
towards the bottom for what the unstable feature flag/prefixes are. For example, towards the bottom for what the unstable feature flag/prefixes are. For example,
a MSC would propose `/_matrix/client/r0/new/endpoint`, not `/_matrix/client/unstable/ an MSC would propose `/_matrix/client/r0/new/endpoint`, not `/_matrix/client/unstable/
com.example/new/endpoint`. com.example/new/endpoint`.
In summary: In summary:
@ -488,7 +488,7 @@ resolve to the desired MSC, whether it started as an issue or a PR.
Other metadata: Other metadata:
- The MSC number is taken from the GitHub Pull Request ID. This is carried for - The MSC number is taken from the GitHub Pull Request ID. This is carried for
the lifetime of the proposal. These IDs do not necessary represent a the lifetime of the proposal. These IDs do not necessarily represent a
chronological order. chronological order.
- The GitHub PR title will act as the MSC's title. - The GitHub PR title will act as the MSC's title.
- Please link to the spec PR (if any) by adding a "PRs: #1234" line in the - Please link to the spec PR (if any) by adding a "PRs: #1234" line in the
@ -496,7 +496,7 @@ Other metadata:
- The creation date is taken from the GitHub PR, but can be overridden by - The creation date is taken from the GitHub PR, but can be overridden by
adding a "Date: yyyy-mm-dd" line in the PR description. adding a "Date: yyyy-mm-dd" line in the PR description.
- Updated Date is taken from GitHub. - Updated Date is taken from GitHub.
- Author is the creator of the MSC PR, but can be overridden by adding a - Author is the creator of the MSC PR, but can be overridden by adding an
"Author: @username" line in the body of the issue description. Please make "Author: @username" line in the body of the issue description. Please make
sure @username is a GitHub user (include the @!) sure @username is a GitHub user (include the @!)
- A shepherd can be assigned by adding a "Shepherd: @username" line in the - A shepherd can be assigned by adding a "Shepherd: @username" line in the

@ -731,7 +731,7 @@ In summary, the remote join handshake consists of the joining server querying
the directory server for information about the room alias; receiving a room ID the directory server for information about the room alias; receiving a room ID
and a list of join candidates. The joining server then requests information and a list of join candidates. The joining server then requests information
about the room from one of the residents. It uses this information to construct about the room from one of the residents. It uses this information to construct
a ``m.room.member`` event which it finally sends to a resident server. an ``m.room.member`` event which it finally sends to a resident server.
Conceptually these are three different roles of homeserver. In practice the Conceptually these are three different roles of homeserver. In practice the
directory server is likely to be resident in the room, and so may be selected directory server is likely to be resident in the room, and so may be selected
@ -822,7 +822,7 @@ Similar to the `Joining Rooms`_ handshake, the server which wishes to leave the
room starts with sending a ``/make_leave`` request to a resident server. In the room starts with sending a ``/make_leave`` request to a resident server. In the
case of rejecting invites, the resident server may be the server which sent the case of rejecting invites, the resident server may be the server which sent the
invite. After receiving a template event from ``/make_leave``, the leaving server invite. After receiving a template event from ``/make_leave``, the leaving server
signs the event and replaces the ``event_id`` with it's own. This is then sent to signs the event and replaces the ``event_id`` with its own. This is then sent to
the resident server via ``/send_leave``. The resident server will then send the the resident server via ``/send_leave``. The resident server will then send the
event to other servers in the room. event to other servers in the room.
@ -837,7 +837,7 @@ Third-party invites
More information about third party invites is available in the `Client-Server API`_ More information about third party invites is available in the `Client-Server API`_
under the Third Party Invites module. under the Third Party Invites module.
When an user wants to invite another user in a room but doesn't know the Matrix When a user wants to invite another user in a room but doesn't know the Matrix
ID to invite, they can do so using a third-party identifier (e.g. an e-mail or a ID to invite, they can do so using a third-party identifier (e.g. an e-mail or a
phone number). phone number).
@ -856,7 +856,7 @@ Cases where an association doesn't exist for a third-party identifier
If the third-party identifier isn't bound to any Matrix ID, the inviting If the third-party identifier isn't bound to any Matrix ID, the inviting
homeserver will request the identity server to store an invite for this identifier homeserver will request the identity server to store an invite for this identifier
and to deliver it to whoever binds it to its Matrix ID. It will also send a and to deliver it to whoever binds it to its Matrix ID. It will also send an
``m.room.third_party_invite`` event in the room to specify a display name, a token ``m.room.third_party_invite`` event in the room to specify a display name, a token
and public keys the identity server provided as a response to the invite storage and public keys the identity server provided as a response to the invite storage
request. request.
@ -867,7 +867,7 @@ in the `Invitation Storage`_ section of the Identity Service API.
The following process applies for each invite sent by the identity server: The following process applies for each invite sent by the identity server:
The invited homeserver will create a ``m.room.member`` invite event containing The invited homeserver will create an ``m.room.member`` invite event containing
a special ``third_party_invite`` section containing the token and a signed object, a special ``third_party_invite`` section containing the token and a signed object,
both provided by the identity server. both provided by the identity server.
@ -882,7 +882,7 @@ will need to request the room's homeserver to auth the event.
Verifying the invite Verifying the invite
++++++++++++++++++++ ++++++++++++++++++++
When a homeserver receives a ``m.room.member`` invite event for a room it's in When a homeserver receives an ``m.room.member`` invite event for a room it's in
with a ``third_party_invite`` object, it must verify that the association between with a ``third_party_invite`` object, it must verify that the association between
the third-party identifier initially invited to the room and the Matrix ID that the third-party identifier initially invited to the room and the Matrix ID that
claims to be bound to it has been verified without having to rely on a third-party claims to be bound to it has been verified without having to rely on a third-party
@ -949,7 +949,7 @@ Receipts are EDUs used to communicate a marker for a given event. Currently the
only kind of receipt supported is a "read receipt", or where in the event graph only kind of receipt supported is a "read receipt", or where in the event graph
the user has read up to. the user has read up to.
Read receipts for events events that a user sent do not need to be sent. It is Read receipts for events that a user sent do not need to be sent. It is
implied that by sending the event the user has read up to the event. implied that by sending the event the user has read up to the event.
{{definition_ss_event_schemas_m_receipt}} {{definition_ss_event_schemas_m_receipt}}

Loading…
Cancel
Save